diff --git a/crm/pengine/complex.c b/crm/pengine/complex.c index f05e03daf9..e3e4ab3a95 100644 --- a/crm/pengine/complex.c +++ b/crm/pengine/complex.c @@ -1,525 +1,519 @@ -/* $Id: complex.c,v 1.73 2006/03/09 21:36:38 andrew Exp $ */ +/* $Id: complex.c,v 1.74 2006/03/18 17:23:48 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 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); extern gboolean rsc_colocation_new(const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh); rsc_to_node_t *generate_location_rule( resource_t *rsc, crm_data_t *location_rule, pe_working_set_t *data_set); void populate_hash(crm_data_t *nvpair_list, GHashTable *hash, const char **attrs, int attrs_length); resource_object_functions_t resource_class_functions[] = { { native_unpack, native_find_child, native_num_allowed_nodes, native_color, native_create_actions, native_create_probe, 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_children, native_parameter, native_print, native_active, native_resource_state, native_create_notify_element, native_free }, { group_unpack, group_find_child, group_num_allowed_nodes, group_color, group_create_actions, group_create_probe, 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_children, native_parameter, group_print, group_active, group_resource_state, group_create_notify_element, group_free }, { clone_unpack, clone_find_child, clone_num_allowed_nodes, clone_color, clone_create_actions, clone_create_probe, clone_internal_constraints, clone_agent_constraints, clone_rsc_colocation_lh, clone_rsc_colocation_rh, clone_rsc_order_lh, clone_rsc_order_rh, clone_rsc_location, clone_expand, clone_children, native_parameter, clone_print, clone_active, clone_resource_state, clone_create_notify_element, clone_free }, { master_unpack, clone_find_child, clone_num_allowed_nodes, clone_color, master_create_actions, clone_create_probe, master_internal_constraints, clone_agent_constraints, clone_rsc_colocation_lh, clone_rsc_colocation_rh, clone_rsc_order_lh, clone_rsc_order_rh, clone_rsc_location, clone_expand, clone_children, native_parameter, clone_print, clone_active, clone_resource_state, clone_create_notify_element, clone_free } }; int get_resource_type(const char *name) { if(safe_str_eq(name, XML_CIB_TAG_RESOURCE)) { return pe_native; } else if(safe_str_eq(name, XML_CIB_TAG_GROUP)) { return pe_group; } else if(safe_str_eq(name, XML_CIB_TAG_INCARNATION)) { return pe_clone; } else if(safe_str_eq(name, XML_CIB_TAG_MASTER)) { return pe_master; } return pe_unknown; } gboolean is_active(rsc_to_node_t *cons) { /* todo: check constraint lifetime */ return TRUE; } static void dup_attr(gpointer key, gpointer value, gpointer user_data) { add_hash_param(user_data, key, value); } gboolean common_unpack(crm_data_t * xml_obj, resource_t **rsc, GHashTable *defaults, pe_working_set_t *data_set) { int lpc = 0; const char *id = crm_element_value(xml_obj, XML_ATTR_ID); const char *value = NULL; const char *allowed_attrs[] = { XML_CIB_ATTR_PRIORITY, XML_RSC_ATTR_INCARNATION_MAX, XML_RSC_ATTR_INCARNATION_NODEMAX, XML_RSC_ATTR_MASTER_MAX, XML_RSC_ATTR_MASTER_NODEMAX, "resource_stickiness" }; const char *rsc_attrs[] = { XML_RSC_ATTR_STOPFAIL, XML_RSC_ATTR_RESTART, "resource_stickiness", "resource_failure_stickiness", "multiple_active", "start_prereq", "is_managed", "globally_unique", "notify" }; crm_log_xml_debug_3(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)->name = 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); for(lpc = 0; lpc < DIMOF(rsc_attrs); lpc++) { value = crm_element_value(xml_obj, rsc_attrs[lpc]); if(value != NULL) { add_hash_param( (*rsc)->parameters, rsc_attrs[lpc], value); } } unpack_instance_attributes( xml_obj, XML_TAG_ATTR_SETS, NULL, (*rsc)->parameters, allowed_attrs, DIMOF(allowed_attrs), data_set); if(defaults != NULL) { g_hash_table_foreach(defaults, dup_attr, (*rsc)->parameters); } (*rsc)->runnable = TRUE; (*rsc)->provisional = TRUE; (*rsc)->starting = FALSE; (*rsc)->stopping = FALSE; (*rsc)->parent = NULL; (*rsc)->candidate_colors = NULL; (*rsc)->rsc_cons = NULL; (*rsc)->actions = NULL; (*rsc)->failed = FALSE; (*rsc)->start_pending = FALSE; (*rsc)->globally_unique = TRUE; (*rsc)->role = RSC_ROLE_STOPPED; (*rsc)->next_role = RSC_ROLE_UNKNOWN; (*rsc)->is_managed = data_set->is_managed_default; (*rsc)->recovery_type = recovery_stop_start; (*rsc)->stickiness = data_set->default_resource_stickiness; (*rsc)->fail_stickiness = data_set->default_resource_fail_stickiness; value = g_hash_table_lookup((*rsc)->parameters, XML_CIB_ATTR_PRIORITY); (*rsc)->priority = crm_parse_int(value, "0"); (*rsc)->effective_priority = (*rsc)->priority; value = g_hash_table_lookup((*rsc)->parameters, "notify"); (*rsc)->notify = crm_is_true(value); value = g_hash_table_lookup((*rsc)->parameters, "is_managed"); if(value != NULL) { cl_str_to_boolean(value, &((*rsc)->is_managed)); } if((*rsc)->is_managed == FALSE) { crm_warn("Resource %s is currently not managed", (*rsc)->id); } else if(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); value = g_hash_table_lookup((*rsc)->parameters, "globally_unique"); if(value != NULL) { cl_str_to_boolean(value, &((*rsc)->globally_unique)); } value = g_hash_table_lookup((*rsc)->parameters, XML_RSC_ATTR_RESTART); if(safe_str_eq(value, "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"); } value = g_hash_table_lookup((*rsc)->parameters, "multiple_active"); if(safe_str_eq(value, "stop_only")) { (*rsc)->recovery_type = recovery_stop_only; crm_debug_2("\tMultiple running resource recovery: stop only"); } else if(safe_str_eq(value, "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"); } value = g_hash_table_lookup((*rsc)->parameters, "resource_stickiness"); if(value != NULL) { (*rsc)->stickiness = char2score(value); } if((*rsc)->stickiness > 0) { crm_debug_2("\tPlacement: prefer current location%s", value == NULL?" (default)":""); } else if((*rsc)->stickiness < 0) { crm_warn("\tPlacement: always move from the current location%s", value == NULL?" (default)":""); } else { crm_debug_2("\tPlacement: optimal%s", value == NULL?" (default)":""); } value = g_hash_table_lookup( (*rsc)->parameters, "resource_failure_stickiness"); if(value != NULL) { (*rsc)->fail_stickiness = char2score(value); } crm_debug_2("\tNode score per failure: %d%s", (*rsc)->fail_stickiness, value == NULL?" (default)":""); crm_debug_2("\tNotification of start/stop actions: %s", (*rsc)->notify?"required":"not required"); /* data_set->resources = g_list_append(data_set->resources, (*rsc)); */ (*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_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); } if(rsc->orphan) { free_xml(rsc->xml); } pe_free_shallow_adv(rsc->running_on, FALSE); pe_free_shallow_adv(rsc->known_on, FALSE); pe_free_shallow_adv(rsc->candidate_colors, TRUE); pe_free_shallow_adv(rsc->rsc_location, FALSE); pe_free_shallow_adv(rsc->allowed_nodes, TRUE); crm_free(rsc->variant_opaque); crm_free(rsc); crm_debug_5("Resource freed"); } void unpack_instance_attributes( crm_data_t *xml_obj, const char *set_name, node_t *node, GHashTable *hash, const char **attrs, int attrs_length, pe_working_set_t *data_set) { crm_data_t *attributes = NULL; if(xml_obj == NULL) { crm_debug_4("No instance attributes"); return; } if(attrs != NULL && attrs[0] == NULL) { /* none allowed */ crm_debug_2("No instance attributes allowed"); return; } crm_debug_2("Checking for attributes"); xml_child_iter_filter( xml_obj, attr_set, set_name, /* check any rules */ if(test_ruleset(attr_set, node, data_set) == FALSE) { continue; } crm_debug_2("Adding attributes"); attributes = cl_get_struct(attr_set, XML_TAG_ATTRS); if(attributes == NULL) { pe_err("%s with no %s child", set_name, XML_TAG_ATTRS); } else { populate_hash(attributes, hash, attrs, attrs_length); } ); } void populate_hash(crm_data_t *nvpair_list, GHashTable *hash, const char **attrs, int attrs_length) { int lpc = 0; gboolean set_attr = FALSE; const char *name = NULL; const char *value = NULL; xml_child_iter_filter( nvpair_list, an_attr, XML_CIB_TAG_NVPAIR, name = crm_element_value(an_attr, XML_NVPAIR_ATTR_NAME); set_attr = TRUE; if(attrs != NULL) { set_attr = FALSE; } for(lpc = 0; set_attr == FALSE && lpc < attrs_length && attrs[lpc] != NULL; lpc++) { if(safe_str_eq(name, attrs[lpc])) { set_attr = TRUE; } } if(set_attr) { crm_debug_4("Setting attribute: %s", name); value = crm_element_value( an_attr, XML_NVPAIR_ATTR_VALUE); add_hash_param(hash, name, value); } else { crm_debug_4("Skipping attribute: %s", name); } ); } void add_rsc_param(resource_t *rsc, const char *name, const char *value) { - CRM_DEV_ASSERT(rsc != NULL); - if(crm_assert_failed) { - return; - } + CRM_CHECK(rsc != NULL, 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_CHECK(hash != NULL, 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)); } } diff --git a/crm/pengine/graph.c b/crm/pengine/graph.c index 6f77247731..2631cf00ec 100644 --- a/crm/pengine/graph.c +++ b/crm/pengine/graph.c @@ -1,566 +1,556 @@ -/* $Id: graph.c,v 1.76 2006/03/09 10:07:53 andrew Exp $ */ +/* $Id: graph.c,v 1.77 2006/03/18 17:23:48 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 gboolean update_action(action_t *action); gboolean update_action_states(GListPtr actions) { crm_debug_2("Updating %d actions", g_list_length(actions)); slist_iter( action, action_t, actions, lpc, update_action(action); ); return TRUE; } #define UPDATE_THEM 1 gboolean update_action(action_t *action) { gboolean change = FALSE; enum action_tasks task = no_action; crm_debug_3("Processing action %s: %s", action->uuid, action->optional?"optional":"required"); slist_iter( other, action_wrapper_t, action->actions_before, lpc, crm_debug_3("\tChecking action %s: %s/%s", other->action->uuid, ordering_type2text(other->type), other->action->optional?"optional":"required"); if(other->type == pe_ordering_restart && action->rsc->role > RSC_ROLE_STOPPED) { crm_debug_3("Upgrading %s constraint to %s", ordering_type2text(other->type), ordering_type2text(pe_ordering_manditory)); other->type = pe_ordering_manditory; } if(other->type != pe_ordering_manditory) { crm_debug_3("\t Ignoring: %s", ordering_type2text(other->type)); continue; } else if(action->optional || other->action->optional == FALSE){ crm_debug_3("\t Ignoring: %s/%s", other->action->optional?"-":"they are not optional", action->optional?"we are optional":"-"); continue; } else if(safe_str_eq(other->action->task, CRMD_ACTION_START)) { const char *interval = g_hash_table_lookup( action->extra, "interval"); int interval_i = 0; if(interval != NULL) { interval_i = crm_parse_int(interval, NULL); if(interval_i > 0) { crm_debug_3("Ignoring: start + recurring"); continue; } } } other->action->optional = FALSE; crm_debug_2("* Marking action %s manditory because of %s", other->action->uuid, action->uuid); update_action(other->action); ); slist_iter( other, action_wrapper_t, action->actions_after, lpc, if(action->pseudo == FALSE && action->runnable == FALSE) { if(other->action->runnable == FALSE) { crm_debug_2("Action %s already un-runnable", other->action->uuid); } else if(action->optional == FALSE) { other->action->runnable = FALSE; crm_debug_2("Marking action %s un-runnable" " because of %s", other->action->uuid, action->uuid); update_action(other->action); } } crm_debug_3("\t(Recover) Checking action %s: %s/%s", other->action->uuid, ordering_type2text(other->type), other->action->optional?"optional":"required"); if(other->action->rsc == NULL) { continue; } else if(other->type == pe_ordering_recover) { if(other->action->rsc->restart_type != pe_restart_restart) { crm_debug_3("\t Ignoring: restart type %d", other->action->rsc->restart_type); continue; } } else if(other->type == pe_ordering_restart) { } else if(other->type == pe_ordering_postnotify) { - CRM_DEV_ASSERT(action->rsc == other->action->rsc); - if(crm_assert_failed) { - continue; - } + CRM_CHECK(action->rsc == other->action->rsc, continue); } else { crm_debug_3("\t Ignoring: ordering %s", ordering_type2text(other->type)); continue; } if(other->action->optional == FALSE || action->optional) { crm_debug_3("\t Ignoring: %s/%s", action->optional?"we are optional":"-", other->action->optional?"-":"they are not optional"); continue; } task = text2task(action->task); switch(task) { case stop_rsc: case stopped_rsc: crm_debug_3("\t Ignoring: action %s", action->uuid); break; case start_rsc: case started_rsc: crm_debug_2("* (Recover) Marking action %s" " manditory because of %s", other->action->uuid, action->uuid); other->action->optional = FALSE; update_action(other->action); break; default: crm_debug_3("\t Ignoring: action %s", action->uuid); break; } ); if(change) { update_action(action); } crm_debug_3("Action %s: %s", action->uuid, change?"update":"untouched"); return change; } gboolean shutdown_constraints( node_t *node, action_t *shutdown_op, pe_working_set_t *data_set) { /* add the stop to the before lists so it counts as a pre-req * for the shutdown */ slist_iter( rsc, resource_t, node->details->running_rsc, lpc, if(rsc->is_managed == FALSE) { continue; } custom_action_order( rsc, stop_key(rsc), NULL, NULL, crm_strdup(CRM_OP_SHUTDOWN), shutdown_op, pe_ordering_manditory, data_set); ); return TRUE; } gboolean stonith_constraints(node_t *node, action_t *stonith_op, action_t *shutdown_op, pe_working_set_t *data_set) { GListPtr stop_actions = NULL; gboolean run_unprotected = TRUE; if(shutdown_op != NULL && stonith_op != NULL) { /* stop everything we can via shutdown_constraints() and then * shoot the node... the shutdown has been superceeded */ shutdown_op->pseudo = TRUE; shutdown_op->runnable = TRUE; /* shutdown before stonith */ /* Give any resources a chance to shutdown normally */ crm_debug_4("Adding shutdown (%d) as an input to stonith (%d)", shutdown_op->id, stonith_op->id); custom_action_order( NULL, crm_strdup(CRM_OP_SHUTDOWN), shutdown_op, NULL, crm_strdup(CRM_OP_FENCE), stonith_op, pe_ordering_manditory, data_set); } /* * Make sure the stonith OP occurs before we start any shared resources */ slist_iter( rsc, resource_t, data_set->resources, lpc, slist_iter(action, action_t, rsc->actions, lpc2, if(action->needs != rsc_req_stonith) { continue; } if(stonith_op != NULL) { custom_action_order( NULL, crm_strdup(CRM_OP_FENCE), stonith_op, rsc, NULL, action, pe_ordering_manditory, data_set); } else if(run_unprotected == FALSE) { /* mark the start unrunnable */ action->runnable = FALSE; } else { pe_err("SHARED RESOURCE %s IS NOT PROTECTED:" " Stonith disabled", rsc->id); } ); ); /* add the stonith OP as a stop pre-req and the mark the stop * as a pseudo op - since its now redundant */ slist_iter( rsc, resource_t, node->details->running_rsc, lpc, if(rsc->is_managed == FALSE) { crm_debug_2("Skipping fencing constraints for unmanaged resource: %s", rsc->id); } else if(stonith_op != NULL) { char *key = stop_key(rsc); stop_actions = find_actions(rsc->actions, key, node); crm_free(key); slist_iter( action, action_t, stop_actions, lpc2, if(node->details->online == FALSE || rsc->failed) { crm_info("Stop of failed resource %s is" " implict after %s is fenced", rsc->id, node->details->uname); /* the stop would never complete and is * now implied by the stonith operation */ action->pseudo = TRUE; action->runnable = TRUE; custom_action_order( NULL, crm_strdup(CRM_OP_FENCE),stonith_op, rsc, start_key(rsc), NULL, pe_ordering_manditory, data_set); } else { crm_info("Moving healthy resource %s" " off %s before fencing", rsc->id, node->details->uname); /* stop healthy resources before the * stonith op */ custom_action_order( rsc, stop_key(rsc), NULL, NULL,crm_strdup(CRM_OP_FENCE),stonith_op, pe_ordering_manditory, data_set); } ); crm_debug_4("Adding stonith (%d) as an input to stop", stonith_op->id); /* } else if((rsc->unclean || node->details->unclean) */ /* && rsc->stopfail_type == pesf_block) { */ /* /\* depend on the stop action which will fail *\/ */ /* pe_err("SHARED RESOURCE %s WILL REMAIN BLOCKED" */ /* " ON NODE %s UNTIL %s", */ /* rsc->id, node->details->uname, */ /* data_set->stonith_enabled?"QUORUM RETURNS":"CLEANED UP MANUALLY"); */ /* continue; */ /* } else if((rsc->unclean || node->details->unclean) */ /* && rsc->stopfail_type == pesf_ignore) { */ /* /\* nothing to do here *\/ */ /* pe_err("SHARED RESOURCE %s IS NOT PROTECTED", rsc->id); */ /* continue; */ } ); return TRUE; } static void dup_attr(gpointer key, gpointer value, gpointer user_data) { g_hash_table_replace(user_data, crm_strdup(key), crm_strdup(value)); } crm_data_t * action2xml(action_t *action, gboolean as_input) { gboolean needs_node_info = TRUE; crm_data_t * action_xml = NULL; crm_data_t * args_xml = NULL; char *action_id_s = NULL; if(action == NULL) { return NULL; } crm_debug_4("Dumping action %d as XML", action->id); if(safe_str_eq(action->task, CRM_OP_FENCE)) { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); /* needs_node_info = FALSE; */ } else if(safe_str_eq(action->task, CRM_OP_SHUTDOWN)) { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); } else if(safe_str_eq(action->task, CRM_OP_LRM_REFRESH)) { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); /* } else if(safe_str_eq(action->task, CRMD_ACTION_PROBED)) { */ /* action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); */ } else if(action->pseudo) { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_PSEUDO_EVENT); needs_node_info = FALSE; } else { action_xml = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP); } action_id_s = crm_itoa(action->id); crm_xml_add(action_xml, XML_ATTR_ID, action_id_s); crm_free(action_id_s); if(action->rsc != NULL) { crm_xml_add( action_xml, XML_LRM_ATTR_RSCID, action->rsc->name); } crm_xml_add(action_xml, XML_LRM_ATTR_TASK, action->task); crm_xml_add(action_xml, XML_LRM_ATTR_TASK_KEY, action->uuid); if(needs_node_info && action->node != NULL) { crm_xml_add(action_xml, XML_LRM_ATTR_TARGET, action->node->details->uname); crm_xml_add(action_xml, XML_LRM_ATTR_TARGET_UUID, - action->node->details->id); - - CRM_DEV_ASSERT(NULL != crm_element_value( - action_xml, XML_LRM_ATTR_TARGET)); - - CRM_DEV_ASSERT(NULL != crm_element_value( - action_xml, XML_LRM_ATTR_TARGET_UUID)); - + action->node->details->id); } if(action->failure_is_fatal == FALSE) { g_hash_table_insert( action->extra, crm_strdup(XML_ATTR_TE_ALLOWFAIL), crm_strdup(XML_BOOLEAN_TRUE)); } if(as_input) { return action_xml; } if(action->notify_keys != NULL) { g_hash_table_foreach( action->notify_keys, dup_attr, action->extra); } if(action->rsc != NULL && action->pseudo == FALSE) { crm_data_t *rsc_xml = create_xml_node( action_xml, crm_element_name(action->rsc->xml)); copy_in_properties(rsc_xml, action->rsc->xml); args_xml = create_xml_node(action_xml, XML_TAG_ATTRS); g_hash_table_foreach(action->extra, hash2field, args_xml); g_hash_table_foreach( action->rsc->parameters, hash2field, args_xml); } else { args_xml = create_xml_node(action_xml, XML_TAG_ATTRS); g_hash_table_foreach(action->extra, hash2field, args_xml); } crm_log_xml_debug_2(action_xml, "dumped action"); return action_xml; } static gboolean should_dump_action(action_t *action) { const char * interval = g_hash_table_lookup(action->extra, "interval"); if(action == NULL) { pe_err("Cannot dump NULL action"); return FALSE; } else if(action->optional) { crm_debug_5("action %d was optional", action->id); return FALSE; } else if(action->pseudo == FALSE && action->runnable == FALSE) { crm_debug_5("action %d was not runnable", action->id); return FALSE; } else if(action->dumped) { crm_debug_5("action %d was already dumped", action->id); return FALSE; } else if(action->rsc != NULL && action->rsc->is_managed == FALSE) { /* make sure probes go through */ if(safe_str_neq(action->task, CRMD_ACTION_STATUS)) { pe_warn("action %d (%s) was for an unmanaged resource (%s)", action->id, action->uuid, action->rsc->id); return FALSE; } if(interval != NULL && safe_str_neq(interval, "0")) { pe_warn("action %d (%s) was for an unmanaged resource (%s)", action->id, action->uuid, action->rsc->id); return FALSE; } } if(action->pseudo || safe_str_eq(action->task, CRM_OP_FENCE) || safe_str_eq(action->task, CRM_OP_SHUTDOWN)) { /* skip the next checks */ return TRUE; } if(action->node == NULL) { pe_err("action %d (%s) was not allocated", action->id, action->uuid); log_action(LOG_DEBUG, "Unallocated action", action, FALSE); return FALSE; } else if(action->node->details->online == FALSE) { pe_err("action %d was (%s) scheduled for offline node", action->id, action->uuid); log_action(LOG_DEBUG, "Action for offline node", action, FALSE); return FALSE; #if 0 /* but this would also affect resources that can be safely * migrated before a fencing op */ } else if(action->node->details->unclean == FALSE) { pe_err("action %d was (%s) scheduled for unclean node", action->id, action->uuid); log_action(LOG_DEBUG, "Action for unclean node", action, FALSE); return FALSE; #endif } return TRUE; } void graph_element_from_action(action_t *action, pe_working_set_t *data_set) { int last_action = -1; int synapse_priority = 0; crm_data_t * syn = NULL; crm_data_t * set = NULL; crm_data_t * in = NULL; crm_data_t * input = NULL; crm_data_t * xml_action = NULL; if(should_dump_action(action) == FALSE) { return; } action->dumped = TRUE; syn = create_xml_node(data_set->graph, "synapse"); set = create_xml_node(syn, "action_set"); in = create_xml_node(syn, "inputs"); crm_xml_add_int(syn, XML_ATTR_ID, data_set->num_synapse); data_set->num_synapse++; if(action->rsc != NULL) { synapse_priority = action->rsc->priority; } if(synapse_priority > 0) { crm_xml_add_int(syn, XML_CIB_ATTR_PRIORITY, synapse_priority); } xml_action = action2xml(action, FALSE); add_node_copy(set, xml_action); free_xml(xml_action); action->actions_before = g_list_sort( action->actions_before, sort_action_id); slist_iter(wrapper,action_wrapper_t,action->actions_before,lpc, if(last_action == wrapper->action->id) { crm_debug_2("Input (%d) %s duplicated", wrapper->action->id, wrapper->action->uuid); continue; } else if(wrapper->action->optional == TRUE) { crm_debug_2("Input (%d) %s optional", wrapper->action->id, wrapper->action->uuid); continue; } - CRM_DEV_ASSERT(last_action < wrapper->action->id); + CRM_CHECK(last_action < wrapper->action->id, ;); last_action = wrapper->action->id; input = create_xml_node(in, "trigger"); xml_action = action2xml(wrapper->action, TRUE); add_node_copy(input, xml_action); free_xml(xml_action); ); } diff --git a/crm/pengine/group.c b/crm/pengine/group.c index 7d20f115df..2392c9160c 100644 --- a/crm/pengine/group.c +++ b/crm/pengine/group.c @@ -1,630 +1,624 @@ -/* $Id: group.c,v 1.53 2006/02/24 11:31:13 andrew Exp $ */ +/* $Id: group.c,v 1.54 2006/03/18 17:23:48 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 extern gboolean rsc_colocation_new( const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh, const char *state_lh, const char *state_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 colocated; gboolean ordered; 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) { resource_t *self = NULL; crm_data_t *xml_obj = rsc->xml; crm_data_t *xml_self = copy_xml(rsc->xml); group_variant_data_t *group_data = NULL; const char *group_ordered = g_hash_table_lookup( rsc->parameters, XML_RSC_ATTR_ORDERED); const char *group_colocated = g_hash_table_lookup( rsc->parameters, "collocated"); crm_debug_3("Processing resource %s...", rsc->id); /* rsc->id = "dummy_group_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; rsc->variant_opaque = group_data; group_data->ordered = TRUE; group_data->colocated = TRUE; if(group_ordered != NULL) { cl_str_to_boolean(group_ordered, &(group_data->ordered)); } if(group_colocated != NULL) { cl_str_to_boolean(group_colocated, &(group_data->colocated)); } /* this is a bit of a hack - but simplifies everything else */ ha_msg_mod(xml_self, F_XML_TAGNAME, XML_CIB_TAG_RESOURCE); /* set_id(xml_self, "self", -1); */ if(common_unpack(xml_self, &self, NULL, 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_filter( xml_obj, xml_native_rsc, XML_CIB_TAG_RESOURCE, resource_t *new_rsc = NULL; if(data_set->short_rsc_names == FALSE) { set_id(xml_native_rsc, group_data->self->id, -1); } if(common_unpack(xml_native_rsc, &new_rsc, group_data->self->parameters, data_set)) { new_rsc->parent = rsc; group_data->num_children++; group_data->child_list = g_list_append( group_data->child_list, new_rsc); if(group_data->first_child == NULL) { group_data->first_child = new_rsc; } else if(group_data->colocated) { rsc_colocation_new( "pe_group_internal_colo", pecs_must, group_data->first_child, new_rsc, NULL, NULL); } group_data->last_child = new_rsc; print_resource(LOG_DEBUG_3, "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, group_data->self->id); } resource_t * group_find_child(resource_t *rsc, const char *id) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); return pe_find_resource(group_data->child_list, id); } GListPtr group_children(resource_t *rsc) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); return group_data->child_list; } int group_num_allowed_nodes(resource_t *rsc) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc); if(group_data->colocated == FALSE) { pe_config_err("Cannot clone non-colocated group: %s", rsc->id); return 0; } return group_data->self->fns->num_allowed_nodes(group_data->self); } color_t * group_color(resource_t *rsc, pe_working_set_t *data_set) { color_t *group_color = 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, group_color = child_rsc->fns->color(child_rsc, data_set); - CRM_DEV_ASSERT(group_color != NULL); + CRM_CHECK(group_color != NULL, continue); native_assign_color(rsc, group_color); ); return group_color; } 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(group_data->self), CRMD_ACTION_STARTED, NULL, !group_data->child_starting, TRUE, 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(group_data->self), CRMD_ACTION_STOPPED, NULL, !group_data->child_stopping, TRUE, data_set); op->pseudo = TRUE; rsc->actions = group_data->self->actions; } 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) && action->runnable) { group_data->child_stopping = TRUE; } else if(safe_str_eq(CRMD_ACTION_START, action->task) && action->runnable) { 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); custom_action_order( group_data->self, stop_key(group_data->self), NULL, group_data->self, stopped_key(group_data->self), NULL, pe_ordering_optional, data_set); custom_action_order( group_data->self, start_key(group_data->self), NULL, group_data->self, started_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(group_data->ordered == FALSE) { order_start_start( group_data->self, child_rsc, pe_ordering_optional); custom_action_order( child_rsc, start_key(child_rsc), NULL, group_data->self, started_key(group_data->self), NULL, pe_ordering_optional, data_set); order_stop_stop( group_data->self, child_rsc, pe_ordering_optional); custom_action_order( child_rsc, stop_key(child_rsc), NULL, group_data->self, stopped_key(group_data->self), NULL, pe_ordering_optional, data_set); continue; } if(last_rsc != NULL) { order_start_start( last_rsc, child_rsc, pe_ordering_optional); order_stop_stop( child_rsc, last_rsc, pe_ordering_optional); /* recovery */ child_rsc->restart_type = pe_restart_restart; order_start_start( last_rsc, child_rsc, pe_ordering_recover); order_stop_stop( child_rsc, last_rsc, pe_ordering_recover); } 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(group_data->ordered && 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( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { group_variant_data_t *group_data = NULL; if(rsc_lh == NULL) { pe_err("rsc_lh was NULL for %s", constraint->id); return; } else if(rsc_rh == NULL) { pe_err("rsc_rh was NULL for %s", constraint->id); return; } crm_debug_4("Processing constraints from %s", rsc_lh->id); get_group_variant_data(group_data, rsc_lh); - CRM_DEV_ASSERT(group_data->self != NULL); - if(crm_assert_failed) { - return; - } + CRM_CHECK(group_data->self != NULL, return); if(group_data->colocated) { group_data->first_child->fns->rsc_colocation_lh( group_data->first_child, rsc_rh, constraint); return; } if(constraint->strength != pecs_must_not) { pe_config_err("Cannot colocate resources with" " non-colocated group: %s", rsc_lh->id); return; } slist_iter( child_rsc, resource_t, group_data->child_list, lpc, child_rsc->fns->rsc_colocation_lh( child_rsc, rsc_rh, constraint); ); } void group_rsc_colocation_rh( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { group_variant_data_t *group_data = NULL; get_group_variant_data(group_data, rsc_rh); - CRM_DEV_ASSERT(group_data->self != NULL); - if(crm_assert_failed) { - return; - } - CRM_DEV_ASSERT(rsc_lh->variant == pe_native); + CRM_CHECK(group_data->self != NULL, return); + CRM_CHECK(rsc_lh->variant == pe_native, return); crm_debug_3("Processing RH of constraint %s", constraint->id); print_resource(LOG_DEBUG_3, "LHS", rsc_lh, TRUE); if(group_data->colocated) { group_data->first_child->fns->rsc_colocation_rh( rsc_lh, group_data->first_child, constraint); return; } if(constraint->strength != pecs_must_not) { pe_config_err("Cannot colocate resources with" " non-colocated group: %s", rsc_rh->id); return; } slist_iter( child_rsc, resource_t, group_data->child_list, lpc, child_rsc->fns->rsc_colocation_rh( rsc_lh, child_rsc, 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(group_data->self); start_id = start_key(group_data->self); if(safe_str_eq(order->lh_action_task, start_id)) { crm_free(order->lh_action_task); order->lh_action_task = started_key(group_data->self); } else if(safe_str_eq(order->lh_action_task, stop_id)) { crm_free(order->lh_action_task); order->lh_action_task = stopped_key(group_data->self); } 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", group_data->self->id); 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", group_data->self->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); ); } gboolean group_active(resource_t *rsc, gboolean all) { 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, gboolean child_active = child_rsc->fns->active(child_rsc, all); if(all == FALSE && child_active) { return TRUE; } else if(child_active == FALSE) { return FALSE; } ); if(all) { return TRUE; } else { return FALSE; } } void group_print( resource_t *rsc, const char *pre_text, long options, void *print_data) { 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 = " "; } status_print("%sResource Group: %s", pre_text?pre_text:"", rsc->id); if(options & pe_print_html) { status_print("\n
    \n"); } else if((options & pe_print_log) == 0) { status_print("\n"); } slist_iter( child_rsc, resource_t, group_data->child_list, lpc, if(options & pe_print_html) { status_print("
  • \n"); } child_rsc->fns->print( child_rsc, child_text, options, print_data); if(options & pe_print_html) { status_print("
  • \n"); } ); if(options & pe_print_html) { status_print("
\n"); } } 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); ); } enum rsc_role_e group_resource_state(resource_t *rsc) { enum rsc_role_e group_role = RSC_ROLE_UNKNOWN; 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, if(child_rsc->next_role > group_role) { group_role = rsc->next_role; } if(child_rsc->failed) { rsc->failed = TRUE; } ); return group_role; } void group_create_notify_element(resource_t *rsc, action_t *op, notify_data_t *n_data, pe_working_set_t *data_set) { 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_notify_element( child_rsc, op, n_data, data_set); ); } gboolean group_create_probe(resource_t *rsc, node_t *node, action_t *complete, pe_working_set_t *data_set) { gboolean any_created = FALSE; 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, any_created = child_rsc->fns->create_probe( child_rsc, node, complete, data_set) || any_created; ); return any_created; } diff --git a/crm/pengine/incarnation.c b/crm/pengine/incarnation.c index 6f9b7fc166..77e73e947a 100644 --- a/crm/pengine/incarnation.c +++ b/crm/pengine/incarnation.c @@ -1,1429 +1,1422 @@ -/* $Id: incarnation.c,v 1.73 2006/02/14 12:01:45 andrew Exp $ */ +/* $Id: incarnation.c,v 1.74 2006/03/18 17:23:48 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 void clone_create_notifications( resource_t *rsc, action_t *action, action_t *action_complete, pe_working_set_t *data_set); extern gboolean rsc_colocation_new( const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh, const char *state_lh, const char *state_rh); typedef struct clone_variant_data_s { resource_t *self; int clone_max; int clone_node_max; int active_clones; int max_nodes; gboolean interleave; gboolean ordered; crm_data_t *xml_obj_child; gboolean notify_confirm; GListPtr child_list; /* resource_t* */ } clone_variant_data_t; void child_stopping_constraints( clone_variant_data_t *clone_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set); void child_starting_constraints( clone_variant_data_t *clone_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set); #define get_clone_variant_data(data, rsc) \ CRM_ASSERT(rsc->variant == pe_clone || rsc->variant == pe_master); \ data = (clone_variant_data_t *)rsc->variant_opaque; static gboolean create_child_clone(resource_t *rsc, int sub_id, pe_working_set_t *data_set) { resource_t *child_rsc = NULL; crm_data_t * child_copy = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); - CRM_DEV_ASSERT(clone_data->xml_obj_child != NULL); + CRM_CHECK(clone_data->xml_obj_child != NULL, return FALSE); child_copy = copy_xml(clone_data->xml_obj_child); if(data_set->short_rsc_names) { set_id(child_copy, NULL, sub_id); } else { set_id(child_copy, rsc->id, sub_id); } if(common_unpack(child_copy, &child_rsc, clone_data->self->parameters, data_set)) { char *inc_num = crm_itoa(sub_id); char *inc_max = crm_itoa(clone_data->clone_max); crm_debug_3("Setting clone attributes for: %s", child_rsc->id); clone_data->child_list = g_list_append( clone_data->child_list, child_rsc); child_rsc->parent = rsc; add_rsc_param( child_rsc, XML_RSC_ATTR_INCARNATION, inc_num); add_rsc_param( child_rsc, XML_RSC_ATTR_INCARNATION_MAX, inc_max); print_resource(LOG_DEBUG_3, "Added", child_rsc, FALSE); crm_free(inc_num); crm_free(inc_max); } else { pe_err("Failed unpacking resource %s", crm_element_value(child_copy, XML_ATTR_ID)); return FALSE; } return TRUE; } void clone_unpack(resource_t *rsc, pe_working_set_t *data_set) { int lpc = 0; crm_data_t * xml_tmp = NULL; crm_data_t * xml_obj = rsc->xml; crm_data_t *xml_self = copy_xml(rsc->xml); clone_variant_data_t *clone_data = NULL; resource_t *self = 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_clones = g_hash_table_lookup( rsc->parameters, XML_RSC_ATTR_INCARNATION_MAX); const char *max_clones_node = g_hash_table_lookup( rsc->parameters, XML_RSC_ATTR_INCARNATION_NODEMAX); crm_debug_3("Processing resource %s...", rsc->id); crm_malloc0(clone_data, sizeof(clone_variant_data_t)); clone_data->child_list = NULL; clone_data->interleave = FALSE; clone_data->ordered = FALSE; clone_data->active_clones = 0; clone_data->xml_obj_child = NULL; clone_data->clone_max = crm_parse_int(max_clones, "1"); clone_data->clone_node_max = crm_parse_int(max_clones_node,"1"); /* this is a bit of a hack - but simplifies everything else */ ha_msg_mod(xml_self, F_XML_TAGNAME, XML_CIB_TAG_RESOURCE); /* set_id(xml_self, "self", -1); */ xml_tmp = find_xml_node(xml_obj, "operations", FALSE); if(xml_tmp != NULL) { add_node_copy(xml_self, xml_tmp); } clone_data->xml_obj_child = find_xml_node( xml_obj, XML_CIB_TAG_GROUP, FALSE); if(clone_data->xml_obj_child == NULL) { clone_data->xml_obj_child = find_xml_node( xml_obj, XML_CIB_TAG_RESOURCE, TRUE); } - CRM_DEV_ASSERT(clone_data->xml_obj_child != NULL); - if(crm_assert_failed) { return; } + CRM_CHECK(clone_data->xml_obj_child != NULL, return); if(common_unpack(xml_self, &self, NULL, data_set)) { clone_data->self = self; } else { crm_log_xml_err(xml_self, "Couldnt unpack dummy child"); return; } if(crm_is_true(interleave)) { clone_data->interleave = TRUE; } if(crm_is_true(ordered)) { clone_data->ordered = TRUE; } clone_data->notify_confirm = clone_data->self->notify; rsc->variant_opaque = clone_data; /* clone_data->gloabally_unique && */ for(lpc = 0; lpc < clone_data->clone_max; lpc++) { create_child_clone(rsc, lpc, data_set); } crm_debug_3("Added %d children to resource %s...", clone_data->clone_max, rsc->id); } resource_t * clone_find_child(resource_t *rsc, const char *id) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); return pe_find_resource(clone_data->child_list, id); } GListPtr clone_children(resource_t *rsc) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); return clone_data->child_list; } int clone_num_allowed_nodes(resource_t *rsc) { int num_nodes = 0; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); /* what *should* we return here? */ slist_iter( child_rsc, resource_t, clone_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; } static gint sort_rsc_provisional(gconstpointer a, gconstpointer b) { const resource_t *resource1 = (const resource_t*)a; const resource_t *resource2 = (const resource_t*)b; CRM_ASSERT(resource1 != NULL); CRM_ASSERT(resource2 != NULL); if(resource1->provisional == resource2->provisional) { return 0; } else if(resource1->provisional) { return 1; } else if(resource2->provisional) { return -1; } - CRM_DEV_ASSERT(FALSE); + CRM_CHECK(FALSE, return 0); return 0; } static gboolean can_run_resources(node_t *node) { if(node->details->online == FALSE || node->details->unclean || node->details->standby) { return FALSE; } return TRUE; } static GListPtr next_color(GListPtr head, GListPtr iter, int max) { color_t *color = NULL; GListPtr local_iter = iter; crm_debug_4("Checking iter: %p", iter); if(local_iter != NULL) { local_iter = local_iter->next; } for(; local_iter != NULL; local_iter = local_iter->next) { color = local_iter->data; crm_debug_5("Color %d: %d", color->details->id, color->details->num_resources); if(color->details->num_resources < max) { return local_iter; } } local_iter = head; crm_debug_4("Now checking head: %p", head); for(; local_iter != NULL; local_iter = local_iter->next) { color = local_iter->data; crm_debug_5("Color %d: %d", color->details->id, color->details->num_resources); if(color->details->num_resources < max) { return local_iter; } } crm_debug_3("Nothing available: %p", head); return NULL; } color_t * clone_color(resource_t *rsc, pe_working_set_t *data_set) { GListPtr color_ptr = NULL; GListPtr child_colors = NULL; int local_node_max = 0; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); if(clone_data->self->provisional == FALSE) { return NULL; } local_node_max = clone_data->clone_node_max; clone_data->max_nodes = rsc->fns->num_allowed_nodes(rsc); /* give already allocated resources every chance to run on the node * specified. other resources can be moved/started where we want * as required */ clone_data->child_list = g_list_sort( clone_data->child_list, sort_rsc_provisional); crm_debug_2("Coloring children of: %s", rsc->id); if(rsc->stickiness <= 0) { while(local_node_max > 1 && clone_data->max_nodes * (local_node_max -1) >= clone_data->clone_max) { local_node_max--; crm_debug("Dropped the effective value of" " clone_node_max to: %d", local_node_max); } } clone_data->self->allowed_nodes = g_list_sort( clone_data->self->allowed_nodes, sort_node_weight); slist_iter(a_node, node_t, clone_data->self->allowed_nodes, lpc, color_t *new_color = NULL; if(can_run_resources(a_node) == FALSE) { crm_debug_2("Node cant run resources: %s", a_node->details->uname); continue; } crm_debug_3("Processing node %s for: %s", a_node->details->uname, rsc->id); new_color = create_color(data_set, NULL, NULL); new_color->details->candidate_nodes = g_list_append( NULL, node_copy(a_node)); slist_iter(child, resource_t, clone_data->child_list, lpc2, node_t *current = NULL; if(child->provisional == FALSE) { - CRM_DEV_ASSERT(child->color != NULL); + CRM_CHECK(child->color != NULL, continue); current = child->color->details->chosen_node; } else if(child->running_on != NULL) { current = child->running_on->data; } if(current == NULL) { crm_debug_2("Not active: %s", child->id); continue; } else if(current->details != a_node->details) { crm_debug_2("Wrong node: %s", child->id); continue; } else if(child->provisional == FALSE) { /* make sure it shows up */ native_assign_color(child, new_color); crm_debug("Previously colored: %s", child->id); continue; } else if(g_list_length(child->running_on) != 1) { crm_debug("active != 1: %s", child->id); continue; } else if(new_color->details->num_resources >= local_node_max) { crm_warn("Node %s too full for: %s", a_node->details->uname, child->id); continue; } native_assign_color(child, new_color); ); native_assign_color(rsc, new_color); child_colors = g_list_append(child_colors, new_color); ); while(local_node_max > 1 && clone_data->max_nodes * (local_node_max -1) >= clone_data->clone_max) { local_node_max--; crm_debug("Dropped the effective value of clone_node_max to: %d", local_node_max); } /* allocate the rest */ slist_iter(child, resource_t, clone_data->child_list, lpc2, if(child->provisional == FALSE) { continue; } crm_debug_2("Processing unalloc'd resource: %s", child->id); color_ptr = next_color( child_colors, color_ptr, local_node_max); if(color_ptr == NULL) { native_assign_color(child, data_set->no_color); } else { native_assign_color(child, color_ptr->data); } ); clone_data->self->provisional = FALSE; return NULL; } static void clone_update_pseudo_status( resource_t *child, gboolean *stopping, gboolean *starting) { CRM_ASSERT(stopping != NULL); CRM_ASSERT(starting != NULL); slist_iter( action, action_t, child->actions, lpc, if(*starting && *stopping) { return; } else if(action->optional) { crm_debug_3("Skipping optional: %s", action->uuid); continue; } else if(action->pseudo == FALSE && action->runnable == FALSE){ crm_debug_3("Skipping unrunnable: %s", action->uuid); continue; } else if(safe_str_eq(CRMD_ACTION_STOP, action->task)) { crm_debug_2("Stopping due to: %s", action->uuid); *stopping = TRUE; } else if(safe_str_eq(CRMD_ACTION_START, action->task)) { if(action->runnable == FALSE) { crm_debug_3("Skipping pseduo-op: %s run=%d, pseudo=%d", action->uuid, action->runnable, action->pseudo); } else { crm_debug_2("Starting due to: %s", action->uuid); crm_debug_3("%s run=%d, pseudo=%d", action->uuid, action->runnable, action->pseudo); *starting = TRUE; } } ); } void clone_create_actions(resource_t *rsc, pe_working_set_t *data_set) { gboolean child_starting = FALSE; gboolean child_stopping = FALSE; action_t *action = NULL; action_t *action_complete = NULL; resource_t *last_start_rsc = NULL; resource_t *last_stop_rsc = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, child_rsc->fns->create_actions(child_rsc, data_set); clone_update_pseudo_status( child_rsc, &child_stopping, &child_starting); if(child_rsc->starting) { last_start_rsc = child_rsc; } if(child_rsc->stopping) { last_stop_rsc = child_rsc; } ); /* start */ action = start_action(clone_data->self, NULL, !child_starting); action_complete = custom_action( clone_data->self, started_key(rsc), CRMD_ACTION_STARTED, NULL, !child_starting, TRUE, data_set); action->pseudo = TRUE; action_complete->pseudo = TRUE; child_starting_constraints(clone_data, pe_ordering_optional, NULL, last_start_rsc, data_set); clone_create_notifications(rsc, action, action_complete, data_set); /* stop */ action = stop_action(clone_data->self, NULL, !child_stopping); action_complete = custom_action( clone_data->self, stopped_key(rsc), CRMD_ACTION_STOPPED, NULL, !child_stopping, TRUE, data_set); action->pseudo = TRUE; action_complete->pseudo = TRUE; child_stopping_constraints(clone_data, pe_ordering_optional, NULL, last_stop_rsc, data_set); clone_create_notifications(rsc, action, action_complete, data_set); rsc->actions = clone_data->self->actions; } void clone_create_notifications( resource_t *rsc, action_t *action, action_t *action_complete, pe_working_set_t *data_set) { /* * pre_notify -> pre_notify_complete -> pseudo_action * -> (real actions) -> pseudo_action_complete * -> post_notify -> post_notify_complete * * if the pre_noitfy requires confirmation, * then a list of confirmations will be added as triggers * to pseudo_action in clone_expand() */ action_t *notify = NULL; action_t *notify_complete = NULL; enum action_tasks task; char *notify_key = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); if(rsc->notify == FALSE) { return; } task = text2task(action->task); /* create pre_notify */ notify_key = generate_notify_key( clone_data->self->id, "pre", action->task); notify = custom_action(clone_data->self, notify_key, CRMD_ACTION_NOTIFY, NULL, action->optional, TRUE, data_set); add_hash_param(notify->extra, "notify_type", "pre"); add_hash_param(notify->extra, "notify_operation", action->task); if(clone_data->notify_confirm) { add_hash_param(notify->extra, "notify_confirm", "yes"); } else { add_hash_param(notify->extra, "notify_confirm", "no"); } notify->pseudo = TRUE; /* create pre_notify_complete */ notify_key = generate_notify_key( clone_data->self->id, "confirmed-pre", action->task); notify_complete = custom_action(clone_data->self, notify_key, CRMD_ACTION_NOTIFIED, NULL, action->optional, TRUE, data_set); add_hash_param(notify_complete->extra, "notify_type", "pre"); add_hash_param(notify_complete->extra, "notify_operation", action->task); if(clone_data->notify_confirm) { add_hash_param(notify->extra, "notify_confirm", "yes"); } else { add_hash_param(notify->extra, "notify_confirm", "no"); } notify->pseudo = TRUE; notify_complete->pseudo = TRUE; /* pre_notify before pre_notify_complete */ custom_action_order( clone_data->self, NULL, notify, clone_data->self, NULL, notify_complete, pe_ordering_manditory, data_set); /* pre_notify_complete before action */ custom_action_order( clone_data->self, NULL, notify_complete, clone_data->self, NULL, action, pe_ordering_manditory, data_set); action->pre_notify = notify; action->pre_notified = notify_complete; /* create post_notify */ notify_key = generate_notify_key (clone_data->self->id, "post", action->task); notify = custom_action(clone_data->self, notify_key, CRMD_ACTION_NOTIFY, NULL, action_complete->optional, TRUE, data_set); add_hash_param(notify->extra, "notify_type", "post"); add_hash_param(notify->extra, "notify_operation", action->task); if(clone_data->notify_confirm) { add_hash_param(notify->extra, "notify_confirm", "yes"); } else { add_hash_param(notify->extra, "notify_confirm", "no"); } notify->pseudo = TRUE; /* action_complete before post_notify */ custom_action_order( clone_data->self, NULL, action_complete, clone_data->self, NULL, notify, pe_ordering_postnotify, data_set); /* create post_notify_complete */ notify_key = generate_notify_key( clone_data->self->id, "confirmed-post", action->task); notify_complete = custom_action(clone_data->self, notify_key, CRMD_ACTION_NOTIFIED, NULL, action->optional, TRUE, data_set); add_hash_param(notify_complete->extra, "notify_type", "pre"); add_hash_param(notify_complete->extra, "notify_operation", action->task); if(clone_data->notify_confirm) { add_hash_param(notify->extra, "notify_confirm", "yes"); } else { add_hash_param(notify->extra, "notify_confirm", "no"); } notify_complete->pseudo = TRUE; /* post_notify before post_notify_complete */ custom_action_order( clone_data->self, NULL, notify, clone_data->self, NULL, notify_complete, pe_ordering_manditory, data_set); action->post_notify = notify; action->post_notified = notify_complete; if(safe_str_eq(action->task, CRMD_ACTION_STOP)) { /* post_notify_complete before start */ custom_action_order( clone_data->self, NULL, notify_complete, clone_data->self, start_key(clone_data->self), NULL, pe_ordering_optional, data_set); } else if(safe_str_eq(action->task, CRMD_ACTION_START)) { /* post_notify_complete before promote */ custom_action_order( clone_data->self, NULL, notify_complete, clone_data->self, promote_key(clone_data->self), NULL, pe_ordering_optional, data_set); } else if(safe_str_eq(action->task, CRMD_ACTION_DEMOTE)) { /* post_notify_complete before promote */ custom_action_order( clone_data->self, NULL, notify_complete, clone_data->self, stop_key(clone_data->self), NULL, pe_ordering_optional, data_set); } } void child_starting_constraints( clone_variant_data_t *clone_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set) { if(clone_data->ordered || clone_data->self->restart_type == pe_restart_restart) { type = pe_ordering_manditory; } if(child == NULL) { if(clone_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, clone_data->self, started_key(clone_data->self), NULL, type, data_set); } } else if(clone_data->ordered) { crm_debug_4("Ordered version"); if(last == NULL) { /* global start before first child start */ last = clone_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, clone_data->self, started_key(clone_data->self), NULL, type, data_set); /* global start before child start */ /* order_start_start(clone_data->self, child, type); */ order_start_start( clone_data->self, child, pe_ordering_manditory); } } void child_stopping_constraints( clone_variant_data_t *clone_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set) { if(clone_data->ordered || clone_data->self->restart_type == pe_restart_restart) { type = pe_ordering_manditory; } if(child == NULL) { if(clone_data->ordered && last != NULL) { crm_debug_4("Ordered version (last node)"); /* global stop before first child stop */ order_stop_stop(clone_data->self, last, pe_ordering_manditory); } } else if(clone_data->ordered && last != NULL) { crm_debug_4("Ordered version"); /* child/child relative stop */ order_stop_stop(child, last, type); } else if(clone_data->ordered) { crm_debug_4("Ordered version (1st node)"); /* first child stop before global stopped */ custom_action_order( child, stop_key(child), NULL, clone_data->self, stopped_key(clone_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, clone_data->self, stopped_key(clone_data->self), NULL, type, data_set); /* global stop before child stop */ order_stop_stop(clone_data->self, child, type); } } void clone_internal_constraints(resource_t *rsc, pe_working_set_t *data_set) { resource_t *last_rsc = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); /* global stop before stopped */ custom_action_order( clone_data->self, stop_key(clone_data->self), NULL, clone_data->self, stopped_key(clone_data->self), NULL, pe_ordering_optional, data_set); /* global start before started */ custom_action_order( clone_data->self, start_key(clone_data->self), NULL, clone_data->self, started_key(clone_data->self), NULL, pe_ordering_optional, data_set); /* global stopped before start */ custom_action_order( clone_data->self, stopped_key(clone_data->self), NULL, clone_data->self, start_key(clone_data->self), NULL, pe_ordering_optional, data_set); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, /* child stop before start */ order_restart(child_rsc); child_starting_constraints( clone_data, pe_ordering_optional, child_rsc, last_rsc, data_set); child_stopping_constraints( clone_data, pe_ordering_optional, child_rsc, last_rsc, data_set); last_rsc = child_rsc; ); } void clone_rsc_colocation_lh( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { gboolean do_interleave = FALSE; resource_t *rsc = constraint->rsc_lh; clone_variant_data_t *clone_data = NULL; clone_variant_data_t *clone_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_clone_variant_data(clone_data, rsc); if(constraint->rsc_rh->variant == pe_clone) { get_clone_variant_data( clone_data_rh, constraint->rsc_rh); if(clone_data->clone_node_max != clone_data_rh->clone_node_max) { pe_err("Cannot interleave "XML_CIB_TAG_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(clone_data->interleave) { do_interleave = TRUE; } else if(constraint->strength != pecs_must_not) { pe_warn("rsc_colocations other than \"-INFINITY\"" " are not supported for non-interleaved " XML_CIB_TAG_INCARNATION" resources"); return; } } else if(constraint->strength != pecs_must_not) { pe_warn("Co-location scores other than \"-INFINITY\" are not " " allowed for non-"XML_CIB_TAG_INCARNATION" resources"); return; } if(do_interleave) { resource_t *child_lh = NULL; resource_t *child_rh = NULL; GListPtr iter_lh = clone_data->child_list; GListPtr iter_rh = clone_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; crm_debug_3("Colocating %s with %s", child_lh->id, child_rh->id); child_lh->fns->rsc_colocation_lh(child_lh, child_rh, constraint); } return; } slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, print_resource(LOG_DEBUG_3, "LHS", child_rsc, TRUE); child_rsc->fns->rsc_colocation_lh(child_rsc, constraint->rsc_rh, constraint); ); } void clone_rsc_colocation_rh( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { clone_variant_data_t *clone_data = NULL; - CRM_DEV_ASSERT(rsc_lh->variant == pe_native); + CRM_CHECK(rsc_lh->variant == pe_native, return); crm_debug_3("Processing RH of constraint %s", constraint->id); if(rsc_lh == NULL) { pe_err("rsc_lh was NULL for %s", constraint->id); return; } else if(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 clone resources"); return; } else { print_resource(LOG_DEBUG_3, "LHS", rsc_lh, FALSE); } get_clone_variant_data(clone_data, rsc_rh); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, print_resource(LOG_DEBUG_3, "RHS", child_rsc, FALSE); child_rsc->fns->rsc_colocation_rh(rsc_lh, child_rsc, constraint); ); } void clone_rsc_order_lh(resource_t *rsc, order_constraint_t *order) { char *stop_id = NULL; char *start_id = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_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); clone_data->self->fns->rsc_order_lh(clone_data->self, order); } void clone_rsc_order_rh( action_t *lh_action, resource_t *rsc, order_constraint_t *order) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); crm_debug_3("Processing RH of ordering constraint %d", order->id); clone_data->self->fns->rsc_order_rh(lh_action, clone_data->self, order); } void clone_rsc_location(resource_t *rsc, rsc_to_node_t *constraint) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); crm_debug_3("Processing actions from %s", rsc->id); clone_data->self->fns->rsc_location(clone_data->self, constraint); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, child_rsc->fns->rsc_location(child_rsc, constraint); ); } static gint sort_notify_entries(gconstpointer a, gconstpointer b) { int tmp; const notify_entry_t *entry_a = a; const notify_entry_t *entry_b = b; if(entry_a == NULL && entry_b == NULL) { return 0; } if(entry_a == NULL) { return 1; } if(entry_b == NULL) { return -1; } if(entry_a->rsc == NULL && entry_b->rsc == NULL) { return 0; } if(entry_a->rsc == NULL) { return 1; } if(entry_b->rsc == NULL) { return -1; } tmp = strcmp(entry_a->rsc->id, entry_b->rsc->id); if(tmp != 0) { return tmp; } if(entry_a->node == NULL && entry_b->node == NULL) { return 0; } if(entry_a->node == NULL) { return 1; } if(entry_b->node == NULL) { return -1; } return strcmp(entry_a->node->details->id, entry_b->node->details->id); } static void expand_list(GListPtr list, int clones, char **rsc_list, char **node_list, char **uuid_list) { int rsc_len = 0; int node_len = 0; int list_len = 100 * clones; char *rsc_list_s = NULL; char *node_list_s = NULL; const char *uname = NULL; const char *rsc_id = NULL; const char *last_rsc_id = NULL; clone_expand_reallocate: if(rsc_list != NULL) { crm_free(*rsc_list); crm_malloc0(*rsc_list, sizeof(char)*list_len); CRM_ASSERT(*rsc_list != NULL); rsc_list_s = *rsc_list; rsc_len = 0; } if(node_list != NULL) { crm_free(*node_list); crm_malloc0(*node_list, sizeof(char)*list_len); CRM_ASSERT(*node_list != NULL); node_list_s = *node_list; node_len = 0; } /* keep BEAM extra happy */ if(rsc_list_s == NULL || node_list_s == NULL) { return; } slist_iter(entry, notify_entry_t, list, lpc, rsc_id = entry->rsc->id; - CRM_DEV_ASSERT(rsc_id != NULL); - if(crm_assert_failed) { - rsc_id = "__none__"; - } + CRM_CHECK(rsc_id != NULL, rsc_id = "__none__"); uname = NULL; if(entry->node) { uname = entry->node->details->uname; } - CRM_DEV_ASSERT(uname != NULL); - if(crm_assert_failed) { - uname = "__none__"; - } + CRM_CHECK(uname != NULL, uname = "__none__"); /* filter dups */ if(safe_str_eq(rsc_id, last_rsc_id)) { continue; } last_rsc_id = rsc_id; if(rsc_list != NULL) { if(rsc_len + 1 + strlen(rsc_id) >= list_len) { list_len *= 2; goto clone_expand_reallocate; } sprintf(rsc_list_s, "%s ", rsc_id); rsc_list_s += strlen(rsc_id); rsc_len += strlen(rsc_id); rsc_list_s++; rsc_len++; } if(node_list != NULL) { if(node_len + 1 + strlen(uname) >= list_len) { list_len *= 2; goto clone_expand_reallocate; } sprintf(node_list_s, "%s ", uname); node_list_s += strlen(uname); node_len += strlen(uname); node_list_s++; node_len++; } ); } void clone_expand(resource_t *rsc, pe_working_set_t *data_set) { char *rsc_list = NULL; char *node_list = NULL; char *uuid_list = NULL; notify_data_t *n_data = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); crm_malloc0(n_data, sizeof(notify_data_t)); n_data->keys = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); crm_debug_2("Processing actions from %s", rsc->id); if(rsc->notify) { slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, slist_iter( op, action_t, clone_data->self->actions, lpc2, child_rsc->fns->create_notify_element( child_rsc, op, n_data, data_set); ); ); } /* expand the notify data */ if(rsc->notify && n_data->stop) { n_data->stop = g_list_sort( n_data->stop, sort_notify_entries); rsc_list = NULL; node_list = NULL; expand_list(n_data->stop, clone_data->clone_max, &rsc_list, &node_list, &uuid_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_stop_resource"), rsc_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_stop_uname"), node_list); } if(rsc->notify && n_data->start) { n_data->start = g_list_sort( n_data->start, sort_notify_entries); rsc_list = NULL; node_list = NULL; expand_list(n_data->start, clone_data->clone_max, &rsc_list, &node_list, &uuid_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_start_resource"), rsc_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_start_uname"), node_list); } if(rsc->notify && n_data->demote) { n_data->demote = g_list_sort( n_data->demote, sort_notify_entries); rsc_list = NULL; node_list = NULL; expand_list(n_data->demote, clone_data->clone_max, &rsc_list, &node_list, &uuid_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_demote_resource"), rsc_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_demote_uname"), node_list); } if(rsc->notify && n_data->promote) { n_data->promote = g_list_sort( n_data->promote, sort_notify_entries); rsc_list = NULL; node_list = NULL; uuid_list = NULL; expand_list(n_data->promote, clone_data->clone_max, &rsc_list, &node_list, &uuid_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_promote_resource"), rsc_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_promote_uname"), node_list); } if(rsc->notify && n_data->active) { n_data->active = g_list_sort( n_data->active, sort_notify_entries); rsc_list = NULL; node_list = NULL; uuid_list = NULL; expand_list(n_data->active, clone_data->clone_max, &rsc_list, &node_list, &uuid_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_active_resource"), rsc_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_active_uname"), node_list); } if(rsc->notify && n_data->slave) { n_data->slave = g_list_sort( n_data->slave, sort_notify_entries); rsc_list = NULL; node_list = NULL; uuid_list = NULL; expand_list(n_data->slave, clone_data->clone_max, &rsc_list, &node_list, &uuid_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_slave_resource"), rsc_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_slave_uname"), node_list); } if(rsc->notify && n_data->master) { n_data->master = g_list_sort( n_data->master, sort_notify_entries); rsc_list = NULL; node_list = NULL; uuid_list = NULL; expand_list(n_data->master, clone_data->clone_max, &rsc_list, &node_list, &uuid_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_master_resource"), rsc_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_master_uname"), node_list); } if(rsc->notify && n_data->inactive) { n_data->inactive = g_list_sort( n_data->inactive, sort_notify_entries); rsc_list = NULL; node_list = NULL; uuid_list = NULL; expand_list(n_data->inactive, clone_data->clone_max, &rsc_list, &node_list, &uuid_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_inactive_resource"), rsc_list); g_hash_table_insert( n_data->keys, crm_strdup("notify_inactive_uname"), node_list); } /* yes, we DO need this second loop */ slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, child_rsc->fns->expand(child_rsc, data_set); ); /* slist_iter( */ /* action, action_t, clone_data->self->actions, lpc2, */ /* if(safe_str_eq(action->task, CRMD_ACTION_NOTIFY)) { */ /* action->extra_xml = notify_xml; */ /* } */ /* ); */ clone_data->self->fns->expand(clone_data->self, data_set); /* destroy the notify_data */ pe_free_shallow(n_data->stop); pe_free_shallow(n_data->start); pe_free_shallow(n_data->demote); pe_free_shallow(n_data->promote); pe_free_shallow(n_data->master); pe_free_shallow(n_data->slave); pe_free_shallow(n_data->active); pe_free_shallow(n_data->inactive); g_hash_table_destroy(n_data->keys); crm_free(n_data); } gboolean clone_active(resource_t *rsc, gboolean all) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, gboolean child_active = child_rsc->fns->active(child_rsc, all); if(all == FALSE && child_active) { return TRUE; } else if(all && child_active == FALSE) { return FALSE; } ); if(all) { return TRUE; } else { return FALSE; } } void clone_print( resource_t *rsc, const char *pre_text, long options, void *print_data) { const char *child_text = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); if(pre_text != NULL) { child_text = " "; } else { child_text = " "; } if(rsc->variant == pe_master) { status_print("%sMaster/Slave Set: %s", pre_text?pre_text:"", clone_data->self->id); } else { status_print("%sClone Set: %s", pre_text?pre_text:"", clone_data->self->id); } if(options & pe_print_html) { status_print("\n
    \n"); } else if((options & pe_print_log) == 0) { status_print("\n"); } slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, if(options & pe_print_html) { status_print("
  • \n"); } child_rsc->fns->print( child_rsc, child_text, options, print_data); if(options & pe_print_html) { status_print("
  • \n"); } ); if(options & pe_print_html) { status_print("
\n"); } } void clone_free(resource_t *rsc) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); crm_debug_3("Freeing %s", rsc->id); slist_iter( child_rsc, resource_t, clone_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(clone_data->child_list, FALSE); free_xml(clone_data->self->xml); clone_data->self->fns->free(clone_data->self); common_free(rsc); } void clone_agent_constraints(resource_t *rsc) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, child_rsc->fns->agent_constraints(child_rsc); ); } enum rsc_role_e clone_resource_state(resource_t *rsc) { return RSC_ROLE_UNKNOWN; } void clone_create_notify_element(resource_t *rsc, action_t *op, notify_data_t *n_data, pe_working_set_t *data_set) { clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, child_rsc->fns->create_notify_element( child_rsc, op, n_data, data_set); ); } static gint sort_rsc_id(gconstpointer a, gconstpointer b) { const resource_t *resource1 = (const resource_t*)a; const resource_t *resource2 = (const resource_t*)b; CRM_ASSERT(resource1 != NULL); CRM_ASSERT(resource2 != NULL); return strcmp(resource1->id, resource2->id); } gboolean clone_create_probe(resource_t *rsc, node_t *node, action_t *complete, pe_working_set_t *data_set) { int num_probes = 0; gboolean any_created = FALSE; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); /* we may already be running but under different names */ slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, if(num_probes >= clone_data->clone_node_max) { return FALSE; } if(pe_find_node_id(child_rsc->running_on, node->details->id)) { num_probes++; } ); clone_data->child_list = g_list_sort( clone_data->child_list, sort_rsc_id); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, if(num_probes >= clone_data->clone_node_max) { break; } if(child_rsc->fns->create_probe( child_rsc, node, complete, data_set)) { any_created = TRUE; num_probes++; } ); return any_created; } diff --git a/crm/pengine/master.c b/crm/pengine/master.c index 812c020a89..2a6f5ee776 100644 --- a/crm/pengine/master.c +++ b/crm/pengine/master.c @@ -1,482 +1,482 @@ -/* $Id: master.c,v 1.9 2006/03/08 15:47:50 andrew Exp $ */ +/* $Id: master.c,v 1.10 2006/03/18 17:23:48 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 void clone_create_notifications( resource_t *rsc, action_t *action, action_t *action_complete, pe_working_set_t *data_set); typedef struct clone_variant_data_s { resource_t *self; int clone_max; int clone_node_max; int active_clones; int max_nodes; gboolean interleave; gboolean ordered; crm_data_t *xml_obj_child; gboolean notify_confirm; GListPtr child_list; /* resource_t* */ } clone_variant_data_t; #define NO_MASTER_PREFS 0 #define get_clone_variant_data(data, rsc) \ CRM_ASSERT(rsc->variant == pe_master); \ data = (clone_variant_data_t *)rsc->variant_opaque; void master_unpack(resource_t *rsc, pe_working_set_t *data_set) { add_hash_param(rsc->parameters, "stateful", XML_BOOLEAN_TRUE); clone_unpack(rsc, data_set); } static void child_promoting_constraints( clone_variant_data_t *clone_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set) { /* if(clone_data->ordered */ /* || clone_data->self->restart_type == pe_restart_restart) { */ /* type = pe_ordering_manditory; */ /* } */ if(child == NULL) { if(clone_data->ordered && last != NULL) { crm_debug_4("Ordered version (last node)"); /* last child promote before promoted started */ custom_action_order( last, promote_key(last), NULL, clone_data->self, promoted_key(clone_data->self), NULL, type, data_set); } } else if(clone_data->ordered) { crm_debug_4("Ordered version"); if(last == NULL) { /* global promote before first child promote */ last = clone_data->self; } /* else: child/child relative promote */ order_start_start(last, child, type); custom_action_order( last, promote_key(last), NULL, child, promote_key(child), NULL, type, data_set); } else { crm_debug_4("Un-ordered version"); /* child promote before global promoted */ custom_action_order( child, promote_key(child), NULL, clone_data->self, promoted_key(clone_data->self), NULL, type, data_set); /* global promote before child promote */ custom_action_order( clone_data->self, promote_key(clone_data->self), NULL, child, promote_key(child), NULL, type, data_set); } } static void child_demoting_constraints( clone_variant_data_t *clone_data, enum pe_ordering type, resource_t *child, resource_t *last, pe_working_set_t *data_set) { /* if(clone_data->ordered */ /* || clone_data->self->restart_type == pe_restart_restart) { */ /* type = pe_ordering_manditory; */ /* } */ if(child == NULL) { if(clone_data->ordered && last != NULL) { crm_debug_4("Ordered version (last node)"); /* global demote before first child demote */ custom_action_order( clone_data->self, demote_key(clone_data->self), NULL, last, demote_key(last), NULL, pe_ordering_manditory, data_set); } } else if(clone_data->ordered && last != NULL) { crm_debug_4("Ordered version"); /* child/child relative demote */ custom_action_order(child, demote_key(child), NULL, last, demote_key(last), NULL, type, data_set); } else if(clone_data->ordered) { crm_debug_4("Ordered version (1st node)"); /* first child stop before global stopped */ custom_action_order( child, demote_key(child), NULL, clone_data->self, demoted_key(clone_data->self), NULL, type, data_set); } else { crm_debug_4("Un-ordered version"); /* child demote before global demoted */ custom_action_order( child, demote_key(child), NULL, clone_data->self, demoted_key(clone_data->self), NULL, type, data_set); /* global demote before child demote */ custom_action_order( clone_data->self, demote_key(clone_data->self), NULL, child, demote_key(child), NULL, type, data_set); } } static void master_update_pseudo_status( resource_t *child, gboolean *demoting, gboolean *promoting) { CRM_ASSERT(demoting != NULL); CRM_ASSERT(promoting != NULL); slist_iter( action, action_t, child->actions, lpc, if(*promoting && *demoting) { return; } else if(action->optional) { continue; } else if(safe_str_eq(CRMD_ACTION_DEMOTE, action->task)) { *demoting = TRUE; } else if(safe_str_eq(CRMD_ACTION_PROMOTE, action->task)) { *promoting = TRUE; } ); } #define apply_master_location(list) \ slist_iter( \ cons, rsc_to_node_t, list, lpc2, \ cons_node = NULL; \ if(cons->role_filter == RSC_ROLE_MASTER) { \ crm_debug("Applying %s to %s", \ cons->id, child_rsc->id); \ cons_node = pe_find_node_id( \ cons->node_list_rh, chosen->details->id); \ } \ if(cons_node != NULL) { \ int new_priority = merge_weights( \ child_rsc->priority, cons_node->weight); \ crm_debug("\t%s: %d->%d", child_rsc->id, \ child_rsc->priority, new_priority); \ child_rsc->priority = new_priority; \ } \ ); struct masters_s { node_t *node; int num_masters; }; void master_create_actions(resource_t *rsc, pe_working_set_t *data_set) { int len = 0; node_t *chosen = NULL; char *attr_name = NULL; const char *attr_value = NULL; node_t *cons_node = NULL; action_t *action = NULL; action_t *action_complete = NULL; gboolean any_promoting = FALSE; gboolean any_demoting = FALSE; resource_t *last_promote_rsc = NULL; resource_t *last_demote_rsc = NULL; const char *master_max_s = g_hash_table_lookup( rsc->parameters, XML_RSC_ATTR_MASTER_MAX); const char *master_node_max_s = g_hash_table_lookup( rsc->parameters, XML_RSC_ATTR_MASTER_NODEMAX); int promoted = 0; int master_max = crm_parse_int(master_max_s, "1"); int master_node_max = crm_parse_int(master_node_max_s, "1"); struct masters_s *master_hash_obj = NULL; GHashTable *master_hash = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); /* how many can we have? */ if(master_max > clone_data->max_nodes * clone_data->clone_node_max) { master_max = clone_data->max_nodes * clone_data->clone_node_max; crm_info("Limited to %d masters (potential slaves)",master_max); } if(master_max > clone_data->max_nodes * master_node_max) { master_max = clone_data->max_nodes * master_node_max; crm_info("Limited to %d masters (available nodes)", master_max); } /* * assign priority */ slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, crm_debug_2("Assigning priority for %s", child_rsc->id); - CRM_DEV_ASSERT(child_rsc->color != NULL); + CRM_CHECK(child_rsc->color != NULL, continue); chosen = child_rsc->color->details->chosen_node; switch(child_rsc->next_role) { case RSC_ROLE_STARTED: if(NO_MASTER_PREFS) { child_rsc->priority = clone_data->clone_max - lpc; break; } child_rsc->priority = -1; - CRM_DEV_ASSERT(chosen != NULL); + CRM_CHECK(chosen != NULL, break); len = 8 + strlen(child_rsc->id); crm_malloc0(attr_name, len); sprintf(attr_name, "master-%s", child_rsc->id); attr_value = g_hash_table_lookup( chosen->details->attrs, attr_name); crm_info("%s=%s for %s", attr_name, crm_str(attr_value), chosen->details->uname); if(attr_value != NULL) { child_rsc->priority = char2score( attr_value); } crm_free(attr_name); apply_master_location(child_rsc->rsc_location); apply_master_location(rsc->rsc_location); break; case RSC_ROLE_SLAVE: case RSC_ROLE_STOPPED: child_rsc->priority = -INFINITY; break; default: - CRM_DEV_ASSERT(FALSE/* unhandled */); + CRM_CHECK(FALSE/* unhandled */, ;); } ); /* sort based on the new "promote" priority */ clone_data->child_list = g_list_sort( clone_data->child_list, sort_rsc_priority); /* mark the first N as masters */ slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, - CRM_DEV_ASSERT(child_rsc->color != NULL); + CRM_CHECK(child_rsc->color != NULL, continue); chosen = child_rsc->color->details->chosen_node; switch(child_rsc->next_role) { case RSC_ROLE_STARTED: master_hash_obj = g_hash_table_lookup( master_hash, chosen->details->id); if(master_hash_obj == NULL) { crm_malloc0(master_hash_obj, sizeof(struct masters_s)); master_hash_obj->node = chosen; g_hash_table_insert( master_hash, crm_strdup(chosen->details->id), master_hash_obj); } if(master_hash_obj->num_masters >= master_node_max) { crm_info("Demoting %s (node master max)", child_rsc->id); child_rsc->next_role = RSC_ROLE_SLAVE; } else if(child_rsc->priority < 0) { crm_info("Demoting %s (priority)", child_rsc->id); child_rsc->next_role = RSC_ROLE_SLAVE; } else if(master_max <= promoted) { crm_info("Demoting %s (masters max)", child_rsc->id); child_rsc->next_role = RSC_ROLE_SLAVE; } else { crm_info("Promoting %s", child_rsc->id); child_rsc->next_role = RSC_ROLE_MASTER; promoted++; master_hash_obj->num_masters++; } break; case RSC_ROLE_SLAVE: if(child_rsc->priority < 0 ||master_max <= lpc){ pe_warn("Cannot promote %s (slave)", child_rsc->id); lpc--; } break; case RSC_ROLE_STOPPED: if(child_rsc->priority < 0 ||master_max <= lpc){ pe_warn("Cannot promote %s (stopping)", child_rsc->id); lpc--; } break; default: - CRM_DEV_ASSERT(FALSE/* unhandled */); + CRM_CHECK(FALSE/* unhandled */, ;); } ); crm_info("Promoted %d (of %d) slaves to master", promoted, master_max); g_hash_table_destroy(master_hash); /* create actions as normal */ clone_create_actions(rsc, data_set); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, gboolean child_promoting = FALSE; gboolean child_demoting = FALSE; master_update_pseudo_status( child_rsc, &child_demoting, &child_promoting); any_demoting = any_demoting || child_demoting; any_promoting = any_promoting || child_promoting; ); /* promote */ action = promote_action(clone_data->self, NULL, !any_promoting); action_complete = custom_action( clone_data->self, promoted_key(rsc), CRMD_ACTION_PROMOTED, NULL, !any_promoting, TRUE, data_set); action->pseudo = TRUE; action_complete->pseudo = TRUE; child_promoting_constraints(clone_data, pe_ordering_optional, NULL, last_promote_rsc, data_set); clone_create_notifications(rsc, action, action_complete, data_set); /* demote */ action = demote_action(clone_data->self, NULL, !any_demoting); action_complete = custom_action( clone_data->self, demoted_key(rsc), CRMD_ACTION_DEMOTED, NULL, !any_demoting, TRUE, data_set); action->pseudo = TRUE; action_complete->pseudo = TRUE; child_demoting_constraints(clone_data, pe_ordering_optional, NULL, last_demote_rsc, data_set); clone_create_notifications(rsc, action, action_complete, data_set); } void master_internal_constraints(resource_t *rsc, pe_working_set_t *data_set) { resource_t *last_rsc = NULL; clone_variant_data_t *clone_data = NULL; get_clone_variant_data(clone_data, rsc); clone_internal_constraints(rsc, data_set); /* global demoted before start */ custom_action_order( clone_data->self, demoted_key(clone_data->self), NULL, clone_data->self, start_key(clone_data->self), NULL, pe_ordering_optional, data_set); /* global started before promote */ custom_action_order( clone_data->self, started_key(clone_data->self), NULL, clone_data->self, promote_key(clone_data->self), NULL, pe_ordering_optional, data_set); /* global demoted before stop */ custom_action_order( clone_data->self, demoted_key(clone_data->self), NULL, clone_data->self, stop_key(clone_data->self), NULL, pe_ordering_optional, data_set); /* global demote before demoted */ custom_action_order( clone_data->self, demote_key(clone_data->self), NULL, clone_data->self, demoted_key(clone_data->self), NULL, pe_ordering_optional, data_set); slist_iter( child_rsc, resource_t, clone_data->child_list, lpc, /* child demote before promote */ custom_action_order( child_rsc, demote_key(child_rsc), NULL, child_rsc, promote_key(child_rsc), NULL, pe_ordering_restart, data_set); child_promoting_constraints(clone_data, pe_ordering_optional, child_rsc, last_rsc, data_set); child_demoting_constraints(clone_data, pe_ordering_optional, child_rsc, last_rsc, data_set); last_rsc = child_rsc; ); } diff --git a/crm/pengine/native.c b/crm/pengine/native.c index d9b2cac0a0..7075039823 100644 --- a/crm/pengine/native.c +++ b/crm/pengine/native.c @@ -1,2011 +1,2001 @@ -/* $Id: native.c,v 1.113 2006/03/09 21:36:38 andrew Exp $ */ +/* $Id: native.c,v 1.114 2006/03/18 17:23:48 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 #define DELETE_THEN_REFRESH 1 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_update_node_weight(resource_t *rsc, rsc_to_node_t *cons, node_t *cons_node, 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_notifications(resource_t *rsc, pe_working_set_t *data_set); void Recurring(resource_t *rsc, action_t *start, node_t *node, pe_working_set_t *data_set); void pe_pre_notify( resource_t *rsc, node_t *node, action_t *op, notify_data_t *n_data, pe_working_set_t *data_set); void pe_post_notify( resource_t *rsc, node_t *node, action_t *op, notify_data_t *n_data, pe_working_set_t *data_set); gboolean DeleteRsc(resource_t *rsc, node_t *node, pe_working_set_t *data_set); void NoRoleChange(resource_t *rsc, node_t *current, node_t *next, pe_working_set_t *data_set); gboolean StopRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set); gboolean StartRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set); gboolean DemoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set); gboolean PromoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set); gboolean RoleError(resource_t *rsc, node_t *next, pe_working_set_t *data_set); gboolean NullOp(resource_t *rsc, node_t *next, pe_working_set_t *data_set); enum rsc_role_e rsc_state_matrix[RSC_ROLE_MAX][RSC_ROLE_MAX] = { /* Current State */ /* Next State: Unknown Stopped Started Slave Master */ /* Unknown */ { RSC_ROLE_UNKNOWN, RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, }, /* Stopped */ { RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STARTED, RSC_ROLE_SLAVE, RSC_ROLE_SLAVE, }, /* Started */ { RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STARTED, RSC_ROLE_SLAVE, RSC_ROLE_UNKNOWN, }, /* Slave */ { RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_UNKNOWN, RSC_ROLE_SLAVE, RSC_ROLE_MASTER, }, /* Master */ { RSC_ROLE_STOPPED, RSC_ROLE_SLAVE, RSC_ROLE_UNKNOWN, RSC_ROLE_SLAVE, RSC_ROLE_MASTER, }, }; gboolean (*rsc_action_matrix[RSC_ROLE_MAX][RSC_ROLE_MAX])(resource_t*,node_t*,pe_working_set_t*) = { /* Current State */ /* Next State: Unknown Stopped Started Slave Master */ /* Unknown */ { RoleError, StopRsc, RoleError, RoleError, RoleError, }, /* Stopped */ { RoleError, NullOp, StartRsc, StartRsc, RoleError, }, /* Started */ { RoleError, StopRsc, NullOp, NullOp, RoleError, }, /* Slave */ { RoleError, StopRsc, RoleError, NullOp, PromoteRsc, }, /* Master */ { RoleError, RoleError, RoleError, DemoteRsc, NullOp, }, }; typedef struct native_variant_data_s { /* 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) { - CRM_DEV_ASSERT(node != NULL); if(crm_assert_failed) { return; } + CRM_CHECK(node != NULL, return); slist_iter( a_node, node_t, rsc->running_on, lpc, - CRM_DEV_ASSERT(a_node != NULL); + CRM_CHECK(a_node != NULL, return); if(safe_str_eq(a_node->details->id, node->details->id)) { return; } ); rsc->running_on = g_list_append(rsc->running_on, node); if(rsc->variant == pe_native) { node->details->running_rsc = g_list_append( node->details->running_rsc, rsc); } if(rsc->variant != pe_native) { } else if(rsc->is_managed == FALSE) { crm_info("resource %s isnt managed", rsc->id); rsc2node_new( "not_managed_default", rsc, INFINITY, node, data_set); return; } else if(rsc->failed) { crm_info("Skipping resource stickiness for failed resource %s", rsc->id); } else if(rsc->stickiness > 0 || rsc->stickiness < 0) { rsc2node_new("stickiness", rsc, rsc->stickiness, node,data_set); crm_debug("Resource %s: preferring current location (%s/%s)", rsc->id, node->details->uname, node->details->id); } if(rsc->variant == pe_native && g_list_length(rsc->running_on) > 1) { const char *type = crm_element_value(rsc->xml, XML_ATTR_TYPE); const char *class = crm_element_value( rsc->xml, XML_AGENT_ATTR_CLASS); /* these are errors because hardly any gets it right * at the moment and this way the might notice */ pe_err("Resource %s::%s:%s appears to be active on %d nodes.", class, type, rsc->id, g_list_length(rsc->running_on)); cl_log(LOG_ERR, "See %s for more information.", HAURL("v2/faq/resource_too_active")); if(rsc->recovery_type == recovery_stop_only) { native_assign_color(rsc, data_set->no_color); } else if(rsc->recovery_type == recovery_block) { rsc->is_managed = FALSE; } } else { crm_debug_2("Resource %s is active on: %s", rsc->id, node->details->uname); } if(rsc->parent != NULL) { native_add_running(rsc->parent, node, data_set); } } void native_unpack(resource_t *rsc, pe_working_set_t *data_set) { native_variant_data_t *native_data = NULL; crm_debug_3("Processing resource %s...", rsc->id); crm_malloc0(native_data, sizeof(native_variant_data_t)); rsc->allowed_nodes = NULL; rsc->running_on = NULL; rsc->variant_opaque = native_data; } resource_t * native_find_child(resource_t *rsc, const char *id) { return NULL; } GListPtr native_children(resource_t *rsc) { return NULL; } static void hash_copy_field(gpointer key, gpointer value, gpointer user_data) { const char *name = key; const char *s_value = value; GHashTable *hash_copy = user_data; g_hash_table_insert(hash_copy, crm_strdup(name), crm_strdup(s_value)); } char * native_parameter( resource_t *rsc, node_t *node, gboolean create, const char *name, pe_working_set_t *data_set) { char *value_copy = NULL; const char *value = NULL; - CRM_DEV_ASSERT(rsc != NULL); - if(crm_assert_failed) { - return NULL; - } + CRM_CHECK(rsc != NULL, return NULL); crm_debug_2("Looking up %s in %s", name, rsc->id); if(create) { GHashTable *local_hash = NULL; if(node != NULL) { crm_debug_2("Creating hash with node %s", node->details->uname); } else { crm_debug_2("Creating default hash"); } local_hash = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); g_hash_table_foreach( rsc->parameters, hash_copy_field, local_hash); unpack_instance_attributes( rsc->xml, XML_TAG_ATTR_SETS, node, local_hash, NULL, 0, data_set); value = g_hash_table_lookup(local_hash, name); if(value != NULL) { value_copy = crm_strdup(value); } g_hash_table_destroy(local_hash); } else { value = g_hash_table_lookup(rsc->parameters, name); if(value != NULL) { value_copy = crm_strdup(value); } } return value_copy; } int native_num_allowed_nodes(resource_t *rsc) { int num_nodes = 0; if(rsc->color) { crm_debug_4("Colored case"); num_nodes = num_allowed_nodes4color(rsc->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, rsc->allowed_nodes, lpc, crm_debug_3("Rsc %s Checking %s: %d", 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: %d", 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; } color_t * native_color(resource_t *rsc, pe_working_set_t *data_set) { color_t *new_color = NULL; print_resource(LOG_DEBUG_2, "Coloring: ", rsc, FALSE); if(rsc->provisional == FALSE) { return rsc->color; } rsc->rsc_cons = g_list_sort( rsc->rsc_cons, sort_cons_strength); /*------ Pre-processing */ slist_iter( constraint, rsc_colocation_t, rsc->rsc_cons, lpc, crm_action_debug_3( print_rsc_colocation( "Pre-Processing constraint", constraint,FALSE)); rsc->fns->rsc_colocation_lh( rsc, constraint->rsc_rh, constraint); ); if( native_choose_color(rsc, data_set->no_color) ) { crm_debug_3("Colored resource %s with color %d", rsc->id, rsc->color->id); new_color = rsc->color; } else { if(rsc->allowed_nodes != NULL) { /* filter out nodes with a negative weight */ filter_nodes(rsc); new_color = create_color(data_set, rsc, rsc->allowed_nodes); native_assign_color(rsc, new_color); } if(new_color == NULL) { pe_warn("Resource %s cannot run anywhere", rsc->id); print_resource(LOG_ERR, "No color: ", rsc, FALSE); native_assign_color(rsc, data_set->no_color); new_color = data_set->no_color; } } rsc->provisional = FALSE; /*------ Post-processing */ #if 1 slist_iter( constraint, rsc_colocation_t, rsc->rsc_cons, lpc, crm_action_debug_3( print_rsc_colocation( "Post-Processing constraint",constraint,FALSE)); rsc->fns->rsc_colocation_lh( rsc, constraint->rsc_rh, constraint); ); #endif print_resource(LOG_DEBUG_3, "Colored", rsc, TRUE); return new_color; } void Recurring(resource_t *rsc, action_t *start, node_t *node, pe_working_set_t *data_set) { char *key = NULL; const char *name = NULL; const char *value = NULL; const char *node_uname = NULL; int interval_ms = 0; action_t *mon = NULL; gboolean is_optional = TRUE; GListPtr possible_matches = NULL; crm_debug_2("Creating recurring actions for %s", rsc->id); if(node != NULL) { node_uname = node->details->uname; } xml_child_iter_filter( rsc->ops_xml, operation, "op", name = crm_element_value(operation, "name"); value = crm_element_value(operation, "interval"); interval_ms = crm_get_msec(value); if(interval_ms <= 0) { continue; } value = crm_element_value(operation, "role"); if(start != NULL && value != NULL && text2role(value) != start->rsc->next_role) { crm_debug_2("Skipping action %s::%s(%s) : %s", start->rsc->id, name, value, role2text(start->rsc->next_role)); continue; } key = generate_op_key(rsc->id, name, interval_ms); if(start != NULL) { crm_debug_3("Marking %s %s due to %s", key, start->optional?"optional":"manditory", start->uuid); is_optional = start->optional; } else { crm_debug_2("Marking %s optional", key); is_optional = TRUE; } /* start a monitor for an already active resource */ possible_matches = find_actions_exact(rsc->actions, key, node); if(possible_matches == NULL) { is_optional = FALSE; crm_debug_3("Marking %s manditory: not active", key); } mon = custom_action(rsc, key, name, node, is_optional, TRUE, data_set); if(is_optional) { crm_debug("%s\t %s (optional)", crm_str(node_uname), mon->uuid); } if(start == NULL || start->runnable == FALSE) { crm_debug("%s\t %s (cancelled : start un-runnable)", crm_str(node_uname), mon->uuid); mon->runnable = FALSE; } else if(node == NULL || node->details->online == FALSE || node->details->unclean) { crm_debug("%s\t %s (cancelled : no node available)", crm_str(node_uname), mon->uuid); mon->runnable = FALSE; } else if(mon->optional == FALSE) { crm_notice("%s\t %s", crm_str(node_uname),mon->uuid); } custom_action_order(rsc, start_key(rsc), NULL, NULL, crm_strdup(key), mon, pe_ordering_restart, data_set); ); } void native_create_actions(resource_t *rsc, pe_working_set_t *data_set) { action_t *start = NULL; node_t *chosen = NULL; enum rsc_role_e role = RSC_ROLE_UNKNOWN; enum rsc_role_e next_role = RSC_ROLE_UNKNOWN; if(rsc->color != NULL) { chosen = rsc->color->details->chosen_node; } unpack_instance_attributes( rsc->xml, XML_TAG_ATTR_SETS, chosen, rsc->parameters, NULL, 0, data_set); crm_debug("%s: %s->%s", rsc->id, role2text(rsc->role), role2text(rsc->next_role)); if(g_list_length(rsc->running_on) > 1) { if(rsc->recovery_type == recovery_stop_start) { pe_err("Attempting recovery of resource %s", rsc->id); StopRsc(rsc, NULL, data_set); rsc->role = RSC_ROLE_STOPPED; } } else if(rsc->running_on != NULL) { node_t *current = rsc->running_on->data; NoRoleChange(rsc, current, chosen, data_set); } else if(rsc->role == RSC_ROLE_STOPPED && rsc->next_role == RSC_ROLE_STOPPED) { char *key = start_key(rsc); GListPtr possible_matches = find_actions(rsc->actions, key, NULL); slist_iter( action, action_t, possible_matches, lpc, action->optional = TRUE; /* action->pseudo = TRUE; */ ); crm_debug_2("Stopping a stopped resource"); crm_free(key); return; } role = rsc->role; while(role != rsc->next_role) { next_role = rsc_state_matrix[role][rsc->next_role]; crm_debug_2("Executing: %s->%s (%s)", role2text(role), role2text(next_role), rsc->id); if(rsc_action_matrix[role][next_role]( rsc, chosen, data_set) == FALSE) { break; } role = next_role; } if(rsc->next_role != RSC_ROLE_STOPPED && rsc->is_managed) { start = start_action(rsc, chosen, TRUE); Recurring(rsc, start, chosen, data_set); } } void native_internal_constraints(resource_t *rsc, pe_working_set_t *data_set) { order_restart(rsc); } void native_rsc_colocation_lh( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { if(rsc_lh == 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; } crm_debug_2("Processing colocation constraint between %s and %s", rsc_lh->id, rsc_rh->id); rsc_rh->fns->rsc_colocation_rh(rsc_lh, rsc_rh, constraint); } static gboolean filter_colocation_constraint( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { if(constraint->strength == pecs_ignore || constraint->strength == pecs_startstop){ crm_debug_4("Skipping constraint type %d", constraint->strength); return FALSE; } if(constraint->state_lh != NULL && text2role(constraint->state_lh) != rsc_lh->next_role) { crm_debug_4("RH: Skipping constraint: \"%s\" state filter", constraint->state_rh); return FALSE; } if(constraint->state_rh != NULL && text2role(constraint->state_rh) != rsc_rh->next_role) { crm_debug_4("RH: Skipping constraint: \"%s\" state filter", constraint->state_rh); return FALSE; } return TRUE; } void native_rsc_colocation_rh( resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint) { gboolean do_check = FALSE; gboolean update_lh = FALSE; gboolean update_rh = FALSE; crm_debug_2("%sColocating %s with %s (%s)", constraint->strength == pecs_must?"":"Anti-", rsc_lh->id, rsc_rh->id, constraint->id); if(filter_colocation_constraint(rsc_lh, rsc_rh, constraint) == FALSE) { return; } if(rsc_lh->provisional && rsc_rh->provisional) { if(constraint->strength == pecs_must) { /* update effective_priorities */ crm_debug_3("Priority update"); 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) && (!rsc_lh->color->details->pending) && (!rsc_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 && rsc_lh->color->details->pending == FALSE) { /* update _them_ : postproc color version */ update_rh = TRUE; } else if(rsc_rh->provisional == FALSE && rsc_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; crm_debug_2("Applying %s (%s) to %s", constraint->id, role2text(constraint->role_filter), rsc->id); /* take "lifetime" into account */ if(constraint == NULL) { pe_err("Constraint is NULL"); return; } else if(rsc == NULL) { pe_err("LHS of rsc_to_node (%s) is NULL", constraint->id); return; } else if(constraint->role_filter > 0 && constraint->role_filter != rsc->next_role) { crm_debug("Constraint (%s) is not active (role : %s)", constraint->id, role2text(constraint->role_filter)); return; } else if(is_active(constraint) == FALSE) { crm_debug_2("Constraint (%s) is not active", constraint->id); return; } if(constraint->node_list_rh == NULL) { crm_debug_2("RHS of constraint %s is NULL", constraint->id); return; } - print_resource(LOG_DEBUG_3, "before update", rsc,TRUE); - + print_resource(LOG_DEBUG_3, "before update: ", rsc, TRUE); or_list = node_list_or( rsc->allowed_nodes, constraint->node_list_rh, FALSE); pe_free_shallow(rsc->allowed_nodes); rsc->allowed_nodes = or_list; slist_iter(node_rh, node_t, constraint->node_list_rh, lpc, native_update_node_weight(rsc, constraint, node_rh, - rsc->allowed_nodes)); + rsc->allowed_nodes) + ); - print_resource(LOG_DEBUG_3, "after update", rsc, TRUE); + print_resource(LOG_DEBUG_3, "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); ); } gboolean native_active(resource_t *rsc, gboolean all) { slist_iter( a_node, node_t, rsc->running_on, lpc, if(a_node->details->online == FALSE) { crm_debug("Resource %s: node %s is offline", rsc->id, a_node->details->uname); } else if(a_node->details->unclean) { crm_debug("Resource %s: node %s is unclean", rsc->id, a_node->details->uname); } else { crm_debug("Resource %s active on %s", rsc->id, a_node->details->uname); return TRUE; } ); return FALSE; } struct print_data_s { long options; void *print_data; }; static void native_print_attr(gpointer key, gpointer value, gpointer user_data) { long options = ((struct print_data_s*)user_data)->options; void *print_data = ((struct print_data_s*)user_data)->print_data; status_print("Option: %s = %s\n", (char*)key, (char*)value); } void native_print( resource_t *rsc, const char *pre_text, long options, void *print_data) { node_t *node = NULL; const char *prov = crm_element_value(rsc->xml,XML_AGENT_ATTR_PROVIDER); if(rsc->running_on != NULL) { node = rsc->running_on->data; } if(options & pe_print_html) { if(rsc->is_managed == FALSE) { status_print(""); } else if(rsc->failed) { status_print(""); } else if(rsc->variant == pe_native && g_list_length(rsc->running_on) == 0) { status_print(""); } else if(g_list_length(rsc->running_on) > 1) { status_print(""); } else { status_print(""); } } if((options & pe_print_rsconly) || g_list_length(rsc->running_on) > 1) { const char *desc = NULL; desc = crm_element_value(rsc->xml, XML_ATTR_DESC); status_print("%s%s (%s%s%s:%s)%s%s", pre_text?pre_text:"", rsc->id, prov?prov:"", prov?"::":"", crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS), crm_element_value(rsc->xml, XML_ATTR_TYPE), desc?": ":"", desc?desc:""); } else { status_print("%s%s (%s%s%s:%s):\t%s%s", pre_text?pre_text:"", rsc->id, prov?prov:"", prov?"::":"", crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS), crm_element_value(rsc->xml, XML_ATTR_TYPE), (rsc->variant!=pe_native)?"":node==NULL?"NOT ACTIVE":node->details->uname, rsc->is_managed?"":" (unmanaged) "); #if CURSES_ENABLED if(options & pe_print_ncurses) { move(-1, 0); } #endif } if(options & pe_print_html) { status_print(" "); } if((options & pe_print_rsconly)) { } else if(g_list_length(rsc->running_on) > 1) { if(options & pe_print_html) { status_print("
    \n"); } else if((options & pe_print_printf) || (options & pe_print_ncurses)) { status_print("["); } slist_iter(node, node_t, rsc->running_on, lpc, if(options & pe_print_html) { status_print("
  • \n%s", node->details->uname); } else if((options & pe_print_printf) || (options & pe_print_ncurses)) { status_print("\t%s", node->details->uname); } else if((options & pe_print_log)) { status_print("\t%d : %s", lpc, node->details->uname); } else { status_print("%s", node->details->uname); } if(options & pe_print_html) { status_print("
  • \n"); } ); if(options & pe_print_html) { status_print("
\n"); } else if((options & pe_print_printf) || (options & pe_print_ncurses)) { status_print(" ]"); } } if(options & pe_print_html) { status_print("
\n"); } else if((options & pe_print_printf) || (options & pe_print_ncurses)) { status_print("\n"); } if(options & pe_print_details) { struct print_data_s pdata; pdata.options = options; pdata.print_data = print_data; g_hash_table_foreach(rsc->parameters, native_print_attr, &pdata); } if(options & pe_print_dev) { status_print("%s\t(%s%svariant=%s, priority=%f)", pre_text, rsc->provisional?"provisional, ":"", rsc->runnable?"":"non-startable, ", crm_element_name(rsc->xml), (double)rsc->priority); status_print("%s\t%d candidate colors, %d allowed nodes," " %d rsc_cons", pre_text, g_list_length(rsc->candidate_colors), g_list_length(rsc->allowed_nodes), g_list_length(rsc->rsc_cons)); } if(options & pe_print_max_details) { status_print("%s\t=== Actions.\n", pre_text); slist_iter( action, action_t, rsc->actions, lpc, log_action(LOG_DEBUG_4, "\trsc action: ", action, FALSE); ); status_print("%s\t=== Colors\n", pre_text); slist_iter( color, color_t, rsc->candidate_colors, lpc, print_color("\t", color, FALSE) ); status_print("%s\t=== Allowed Nodes\n", pre_text); slist_iter( node, node_t, rsc->allowed_nodes, lpc, print_node("\t", node, FALSE); ); } } void native_free(resource_t *rsc) { crm_debug_4("Freeing Allowed Nodes"); crm_free(rsc->color); common_free(rsc); } void native_rsc_colocation_rh_must(resource_t *rsc_lh, gboolean update_lh, resource_t *rsc_rh, gboolean update_rh) { gboolean do_merge = FALSE; GListPtr old_list = NULL; GListPtr merged_node_list = NULL; int 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; crm_debug_2("Colocating %s with %s." " Update LHS: %s, Update RHS: %s", rsc_lh->id, rsc_rh->id, update_lh?"true":"false", update_rh?"true":"false"); if(rsc_lh->color && rsc_rh->color) { do_merge = TRUE; merged_node_list = node_list_and( rsc_lh->color->details->candidate_nodes, rsc_rh->color->details->candidate_nodes, TRUE); } else if(rsc_lh->color) { do_merge = TRUE; merged_node_list = node_list_and( rsc_lh->color->details->candidate_nodes, rsc_rh->allowed_nodes, TRUE); } else if(rsc_rh->color) { do_merge = TRUE; merged_node_list = node_list_and( rsc_lh->allowed_nodes, rsc_rh->color->details->candidate_nodes, TRUE); } if(update_lh && rsc_rh != rsc_lh) { - CRM_DEV_ASSERT(rsc_lh->color != rsc_rh->color); + CRM_CHECK(rsc_lh->color != rsc_rh->color, return); crm_free(rsc_lh->color); rsc_lh->runnable = rsc_rh->runnable; rsc_lh->provisional = rsc_rh->provisional; - CRM_DEV_ASSERT(rsc_rh->color != NULL); + CRM_CHECK(rsc_rh->color != NULL, return); native_assign_color(rsc_lh, rsc_rh->color); } if(update_rh && rsc_rh != rsc_lh) { - CRM_DEV_ASSERT(rsc_lh->color != rsc_rh->color); + CRM_CHECK(rsc_lh->color != rsc_rh->color, return); crm_free(rsc_rh->color); rsc_rh->runnable = rsc_lh->runnable; rsc_rh->provisional = rsc_lh->provisional; - CRM_DEV_ASSERT(rsc_lh->color != NULL); + CRM_CHECK(rsc_lh->color != NULL, return); native_assign_color(rsc_rh, rsc_lh->color); } if((update_rh || update_lh) && do_merge) { crm_debug_4("Merging candidate nodes"); old_list = rsc_rh->color->details->candidate_nodes; rsc_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; crm_debug_4("Processing pecs_must_not constraint"); /* pecs_must_not */ color_rh = rsc_rh->color; color_lh = rsc_lh->color; if(update_lh) { if(rsc_lh->provisional && color_rh != NULL) { color_lh = add_color(rsc_lh, color_rh); color_lh->local_weight = -INFINITY; crm_debug_2("LH: Removed color %d from resource %s", color_lh->id, rsc_lh->id); crm_action_debug_3( print_color("Removed LH", color_lh, FALSE)); print_resource(LOG_DEBUG_3, "Modified LH", rsc_lh,TRUE); } else if(rsc_lh->provisional) { } else if(color_lh && color_lh->details->pending) { node_t *node_lh = NULL; node_lh = pe_find_node_id( color_lh->details->candidate_nodes, safe_val5(NULL, color_rh, details, chosen_node, details, id)); if(node_lh != NULL) { node_lh->weight = -INFINITY; crm_debug_2("LH: Removed node %s from color %d", node_lh->details->uname, color_lh->id); crm_action_debug_3( print_node("Removed LH", node_lh, FALSE)); crm_action_debug_3( print_color("Modified LH", color_lh, FALSE)); } } else { /* error, rsc marked as unrunnable above */ pe_warn("lh else"); } } /* in case anything was modified */ color_rh = rsc_rh->color; color_lh = rsc_lh->color; if(update_rh) { if(rsc_rh->provisional && color_lh != NULL) { color_rh = add_color(rsc_lh, color_lh); color_rh->local_weight = -INFINITY; crm_debug_2("RH: Removed color %d from resource %s", color_rh->id, rsc_rh->id); crm_action_debug_3( print_color("Removed RH", color_rh, FALSE)); print_resource(LOG_DEBUG_3, "Modified RH", rsc_rh, TRUE); } else if(rsc_rh->provisional) { } else if(color_rh && color_rh->details->pending) { node_t *node_rh = NULL; node_rh = pe_find_node_id( color_rh->details->candidate_nodes, safe_val5(NULL, color_lh, details, chosen_node, details, id)); if(node_rh != NULL) { node_rh->weight = -INFINITY; crm_debug_2("RH: Removed node %s from color %d", node_rh->details->uname, color_rh->id); crm_action_debug_3( print_node("Removed RH", node_rh, FALSE)); crm_action_debug_3( print_color("Modified RH", color_rh, FALSE)); } } else { /* error, rsc marked as unrunnable above */ pe_warn("rh else"); } } } void native_agent_constraints(resource_t *rsc) { } gboolean native_choose_color(resource_t *rsc, color_t *no_color) { GListPtr sorted_colors = NULL; 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_2("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(this_color->local_weight < 0) { /* no valid color available */ crm_debug("no valid color available"); break; } else if(rsc->effective_priority < this_color->details->highest_priority) { minus = node_list_minus( this_color->details->candidate_nodes, rsc->allowed_nodes, TRUE); len = g_list_length(minus); pe_free_shallow(minus); } else { intersection = node_list_and( this_color->details->candidate_nodes, rsc->allowed_nodes, TRUE); len = g_list_length(intersection); pe_free_shallow(intersection); } if(len > 0) { crm_debug("Assigning color to %s", rsc->id); 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; rsc->provisional = FALSE; - CRM_DEV_ASSERT(local_color != NULL); - if (crm_assert_failed) { - pe_err("local color was NULL"); - return; - } + CRM_CHECK(local_color != NULL, return); local_color->details->allocated_resources = g_list_append(local_color->details->allocated_resources,rsc); if(rsc->variant == pe_native) { (local_color->details->num_resources)++; rsc->color = copy_color(local_color); crm_debug_3("Created intersection for color %d", local_color->id); intersection = node_list_and( local_color->details->candidate_nodes, rsc->allowed_nodes, FALSE); old_list = local_color->details->candidate_nodes; pe_free_shallow(old_list); local_color->details->candidate_nodes = intersection; } crm_debug_2("Colored resource %s with color %d", rsc->id, local_color->id); print_resource(LOG_DEBUG_3, "Colored Resource", rsc, TRUE); return; } void native_update_node_weight(resource_t *rsc, rsc_to_node_t *cons, node_t *cons_node, GListPtr nodes) { node_t *node_rh = NULL; - CRM_DEV_ASSERT(cons_node != NULL); + CRM_CHECK(cons_node != NULL, return); node_rh = pe_find_node_id( rsc->allowed_nodes, cons_node->details->id); if(node_rh == NULL) { pe_err("Node not found - adding %s to %s", cons_node->details->id, rsc->id); node_rh = node_copy(cons_node); rsc->allowed_nodes = g_list_append( rsc->allowed_nodes, node_rh); node_rh = pe_find_node_id( rsc->allowed_nodes, cons_node->details->id); - CRM_DEV_ASSERT(node_rh != NULL); + CRM_CHECK(node_rh != NULL, return); return; } - CRM_DEV_ASSERT(node_rh != NULL); + CRM_CHECK(node_rh != NULL, return); if(node_rh == NULL) { pe_err("Node not found - cant update"); return; } if(node_rh->weight >= INFINITY && cons_node->weight <= -INFINITY) { pe_err("Constraint \"%s\" mixes +/- INFINITY (%s)", cons->id, rsc->id); } else if(node_rh->details->shutdown == TRUE || node_rh->details->online == FALSE || node_rh->details->unclean == TRUE) { } else if(node_rh->weight <= -INFINITY && cons_node->weight >= INFINITY) { pe_err("Constraint \"%s\" mixes +/- INFINITY (%s)", cons->id, rsc->id); } if(node_rh->fixed) { /* warning */ crm_debug_2("Constraint %s is irrelevant as the" " weight of node %s is fixed as %d (%s).", cons->id, node_rh->details->uname, node_rh->weight, rsc->id); return; } node_rh->weight = merge_weights(node_rh->weight, cons_node->weight); if(node_rh->weight <= -INFINITY) { crm_debug_3("Constraint %s (-INFINITY): node %s weight %d (%s).", cons->id, node_rh->details->uname, node_rh->weight, rsc->id); } else if(node_rh->weight >= INFINITY) { crm_debug_3("Constraint %s (+INFINITY): node %s weight %d (%s).", cons->id, node_rh->details->uname, node_rh->weight, rsc->id); } else { crm_debug_3("Constraint %s (%d): node %s weight %d (%s).", cons->id, cons_node->weight, node_rh->details->uname, node_rh->weight, rsc->id); } 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) { 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; color_lh = rsc_lh->color; color_rh = rsc_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) { - print_resource(LOG_DEBUG_3, "Filtering nodes for", rsc, FALSE); + print_resource(LOG_DEBUG_3, "Filtering nodes for: ", rsc, FALSE); slist_iter( node, node_t, rsc->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)); rsc->allowed_nodes = g_list_remove(rsc->allowed_nodes, node); crm_free(node); lpc = -1; /* restart the loop */ } ); } enum rsc_role_e native_resource_state(resource_t *rsc) { if(rsc->next_role != RSC_ROLE_UNKNOWN) { return rsc->next_role; } if(rsc->role != RSC_ROLE_UNKNOWN) { return rsc->role; } return RSC_ROLE_STOPPED; } void create_notifications(resource_t *rsc, pe_working_set_t *data_set) { if(rsc->notify == FALSE) { return; } /* slist_iter( */ /* action, action_t, rsc->actions, lpc, */ /* ); */ } static void register_activity(resource_t *rsc, enum action_tasks task, node_t *node, notify_data_t *n_data) { notify_entry_t *entry = NULL; crm_malloc0(entry, sizeof(notify_entry_t)); entry->rsc = rsc; entry->node = node; switch(task) { case start_rsc: n_data->start = g_list_append(n_data->start, entry); break; case stop_rsc: n_data->stop = g_list_append(n_data->stop, entry); break; case action_promote: n_data->promote = g_list_append(n_data->promote, entry); break; case action_demote: n_data->demote = g_list_append(n_data->demote, entry); break; default: crm_err("Unsupported notify action: %s", task2text(task)); break; } } static void register_state(resource_t *rsc, node_t *on_node, notify_data_t *n_data) { notify_entry_t *entry = NULL; crm_malloc0(entry, sizeof(notify_entry_t)); entry->rsc = rsc; entry->node = on_node; crm_err("%s state: %s", rsc->id, role2text(rsc->next_role)); switch(rsc->next_role) { case RSC_ROLE_STOPPED: /* n_data->inactive = g_list_append(n_data->inactive, entry); */ crm_free(entry); break; case RSC_ROLE_STARTED: n_data->active = g_list_append(n_data->active, entry); break; case RSC_ROLE_SLAVE: n_data->slave = g_list_append(n_data->slave, entry); break; case RSC_ROLE_MASTER: n_data->master = g_list_append(n_data->master, entry); break; default: crm_err("Unsupported notify role"); break; } } void native_create_notify_element(resource_t *rsc, action_t *op, notify_data_t *n_data, pe_working_set_t *data_set) { node_t *next_node = NULL; gboolean registered = FALSE; char *op_key = NULL; GListPtr possible_matches = NULL; enum action_tasks task = text2task(op->task); if(op->pre_notify == NULL || op->post_notify == NULL) { /* no notifications required */ crm_debug_4("No notificaitons required for %s", op->task); return; } next_node = rsc->color->details->chosen_node; op_key = generate_op_key(rsc->id, op->task, 0); possible_matches = find_actions(rsc->actions, op_key, NULL); crm_debug_2("Creating notificaitons for: %s (%s->%s)", op->uuid, role2text(rsc->role), role2text(rsc->next_role)); if(rsc->role == rsc->next_role) { register_state(rsc, next_node, n_data); } slist_iter( local_op, action_t, possible_matches, lpc, local_op->notify_keys = n_data->keys; if(local_op->optional == FALSE) { registered = TRUE; register_activity(rsc, task, local_op->node, n_data); } ); /* stop / demote */ if(rsc->role != RSC_ROLE_STOPPED) { if(task == stop_rsc || task == action_demote) { slist_iter( current_node, node_t, rsc->running_on, lpc, pe_pre_notify(rsc, current_node, op, n_data, data_set); if(task == action_demote || registered == FALSE) { pe_post_notify(rsc, current_node, op, n_data, data_set); } ); } } /* start / promote */ if(rsc->next_role != RSC_ROLE_STOPPED) { - CRM_DEV_ASSERT(next_node != NULL); + CRM_CHECK(next_node != NULL, return); if(task == start_rsc || task == action_promote) { if(task != start_rsc || registered == FALSE) { pe_pre_notify(rsc, next_node, op, n_data, data_set); } pe_post_notify(rsc, next_node, op, n_data, data_set); } } crm_free(op_key); pe_free_shallow_adv(possible_matches, FALSE); } static void dup_attr(gpointer key, gpointer value, gpointer user_data) { g_hash_table_replace(user_data, crm_strdup(key), crm_strdup(value)); } static void pe_notify(resource_t *rsc, node_t *node, action_t *op, action_t *confirm, notify_data_t *n_data, pe_working_set_t *data_set) { char *key = NULL; action_t *trigger = NULL; action_wrapper_t *wrapper = NULL; const char *value = NULL; const char *task = NULL; if(op == NULL || confirm == NULL) { crm_debug_2("Op=%p confirm=%p", op, confirm); return; } - CRM_DEV_ASSERT(node != NULL); + CRM_CHECK(node != NULL, return); value = g_hash_table_lookup(op->extra, "notify_type"); task = g_hash_table_lookup(op->extra, "notify_operation"); crm_debug_2("Creating actions for %s: %s (%s-%s)", op->uuid, rsc->id, value, task); key = generate_notify_key(rsc->id, value, task); trigger = custom_action(rsc, key, op->task, node, op->optional, TRUE, data_set); g_hash_table_foreach(op->extra, dup_attr, trigger->extra); trigger->notify_keys = n_data->keys; /* pseudo_notify before notify */ crm_debug_3("Ordering %s before %s (%d->%d)", op->uuid, trigger->uuid, trigger->id, op->id); crm_malloc0(wrapper, sizeof(action_wrapper_t)); wrapper->action = op; wrapper->type = pe_ordering_manditory; trigger->actions_before=g_list_append(trigger->actions_before, wrapper); wrapper = NULL; crm_malloc0(wrapper, sizeof(action_wrapper_t)); wrapper->action = trigger; wrapper->type = pe_ordering_manditory; op->actions_after = g_list_append(op->actions_after, wrapper); value = g_hash_table_lookup(op->extra, "notify_confirm"); if(crm_is_true(value)) { /* notify before pseudo_notified */ crm_debug_3("Ordering %s before %s (%d->%d)", trigger->uuid, confirm->uuid, confirm->id, trigger->id); wrapper = NULL; crm_malloc0(wrapper, sizeof(action_wrapper_t)); wrapper->action = trigger; wrapper->type = pe_ordering_manditory; confirm->actions_before = g_list_append( confirm->actions_before, wrapper); wrapper = NULL; crm_malloc0(wrapper, sizeof(action_wrapper_t)); wrapper->action = confirm; wrapper->type = pe_ordering_manditory; trigger->actions_after = g_list_append( trigger->actions_after, wrapper); } } void pe_pre_notify(resource_t *rsc, node_t *node, action_t *op, notify_data_t *n_data, pe_working_set_t *data_set) { crm_debug_2("%s: %s", rsc->id, op->uuid); pe_notify(rsc, node, op->pre_notify, op->pre_notified, n_data, data_set); } void pe_post_notify(resource_t *rsc, node_t *node, action_t *op, notify_data_t *n_data, pe_working_set_t *data_set) { crm_debug_2("%s: %s", rsc->id, op->uuid); pe_notify(rsc, node, op->post_notify, op->post_notified, n_data, data_set); } void NoRoleChange(resource_t *rsc, node_t *current, node_t *next, pe_working_set_t *data_set) { action_t *start = NULL; action_t *stop = NULL; crm_debug("Executing: %s (role=%s)",rsc->id, role2text(rsc->next_role)); if(current == NULL || next == NULL) { return; } /* use StartRsc/StopRsc */ if(safe_str_neq(current->details->id, next->details->id)) { crm_notice("Move resource %s\t(%s -> %s)", rsc->id, current->details->uname, next->details->uname); stop = stop_action(rsc, current, FALSE); start = start_action(rsc, next, FALSE); if(data_set->remove_after_stop) { DeleteRsc(rsc, current, data_set); } } else { if(rsc->failed) { crm_notice("Recover resource %s\t(%s)", rsc->id, next->details->uname); stop = stop_action(rsc, current, FALSE); start = start_action(rsc, next, FALSE); /* /\* make the restart required *\/ */ /* order_stop_start(rsc, rsc, pe_ordering_manditory); */ } else if(rsc->start_pending) { start = start_action(rsc, next, TRUE); if(start->runnable) { /* wait for StartRsc() to be called */ rsc->role = RSC_ROLE_STOPPED; } else { /* wait for StopRsc() to be called */ rsc->next_role = RSC_ROLE_STOPPED; } } else { stop = stop_action(rsc, current, TRUE); start = start_action(rsc, next, TRUE); stop->optional = start->optional; if(start->runnable == FALSE) { rsc->next_role = RSC_ROLE_STOPPED; } else if(start->optional) { crm_notice("Leave resource %s\t(%s)", rsc->id, next->details->uname); } else { crm_notice("Restart resource %s\t(%s)", rsc->id, next->details->uname); } } } } gboolean StopRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set) { action_t *stop = NULL; crm_debug_2("Executing: %s", rsc->id); slist_iter( current, node_t, rsc->running_on, lpc, crm_notice(" %s\tStop %s", current->details->uname, rsc->id); stop = stop_action(rsc, current, FALSE); if(data_set->remove_after_stop) { DeleteRsc(rsc, current, data_set); } ); return TRUE; } gboolean DeleteRsc(resource_t *rsc, node_t *node, pe_working_set_t *data_set) { action_t *delete = NULL; action_t *refresh = NULL; char *stop = NULL; char *start = NULL; if(rsc->failed) { crm_debug_2("Resource %s not deleted from %s: failed", rsc->name, node->details->uname); return FALSE; } else if(node == NULL) { crm_debug_2("Resource %s not deleted: NULL node", rsc->name); return FALSE; } else if(node->details->unclean || node->details->online == FALSE) { crm_debug_2("Resource %s not deleted from %s: unrunnable", rsc->name, node->details->uname); return FALSE; } stop = stop_key(rsc); start = start_key(rsc); crm_notice("Removing %s from %s", rsc->name, node->details->uname); delete = delete_action(rsc, node); custom_action_order( rsc, stop, NULL, rsc, NULL, delete, pe_ordering_optional, data_set); custom_action_order( rsc, NULL, delete, rsc, start, NULL, pe_ordering_manditory, data_set); #if DELETE_THEN_REFRESH refresh = custom_action( NULL, crm_strdup(CRM_OP_LRM_REFRESH), CRM_OP_LRM_REFRESH, node, FALSE, TRUE, data_set); add_hash_param(refresh->extra, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE); custom_action_order( rsc, NULL, delete, NULL, NULL, refresh, pe_ordering_optional, data_set); #endif return TRUE; } gboolean StartRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set) { action_t *start = NULL; crm_debug_2("Executing: %s", rsc->id); start = start_action(rsc, next, TRUE); if(start->runnable) { crm_notice(" %s\tStart %s", next->details->uname, rsc->id); start->optional = FALSE; } return TRUE; } gboolean PromoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set) { crm_debug_2("Executing: %s", rsc->id); - CRM_DEV_ASSERT(rsc->next_role == RSC_ROLE_MASTER); + CRM_CHECK(rsc->next_role == RSC_ROLE_MASTER, return FALSE); crm_notice("%s\tPromote %s", next->details->uname, rsc->id); promote_action(rsc, next, FALSE); return TRUE; } gboolean DemoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set) { crm_debug_2("Executing: %s", rsc->id); - CRM_DEV_ASSERT(rsc->next_role == RSC_ROLE_SLAVE); + CRM_CHECK(rsc->next_role == RSC_ROLE_SLAVE, return FALSE); slist_iter( current, node_t, rsc->running_on, lpc, crm_notice("%s\tDeomote %s", next->details->uname, rsc->id); demote_action(rsc, current, FALSE); ); return TRUE; } gboolean RoleError(resource_t *rsc, node_t *next, pe_working_set_t *data_set) { crm_debug("Executing: %s", rsc->id); - CRM_DEV_ASSERT(FALSE); + CRM_CHECK(FALSE, return FALSE); return FALSE; } gboolean NullOp(resource_t *rsc, node_t *next, pe_working_set_t *data_set) { crm_debug("Executing: %s", rsc->id); return FALSE; } gboolean native_create_probe(resource_t *rsc, node_t *node, action_t *complete, pe_working_set_t *data_set) { char *key = NULL; char *target_rc = NULL; action_t *probe = NULL; node_t *running = NULL; - CRM_DEV_ASSERT(node != NULL); - if(crm_assert_failed) { - return FALSE; - } + CRM_CHECK(node != NULL, return FALSE); running = pe_find_node_id(rsc->known_on, node->details->id); if(running != NULL) { /* we already know the status of the resource on this node */ return FALSE; } target_rc = crm_itoa(EXECRA_NOT_RUNNING); key = generate_op_key(rsc->id, CRMD_ACTION_STATUS, 0); probe = custom_action(rsc, key, CRMD_ACTION_STATUS, node, FALSE, TRUE, data_set); crm_notice("%s: Created probe for %s", node->details->uname, rsc->id); g_hash_table_insert(probe->extra, crm_strdup(XML_ATTR_TE_TARGET_RC), target_rc); g_hash_table_insert(probe->extra, crm_strdup(XML_ATTR_LRM_PROBE), crm_strdup(XML_BOOLEAN_TRUE)); custom_action_order(rsc, NULL, probe, rsc, NULL, complete, pe_ordering_manditory, data_set); return TRUE; } diff --git a/crm/pengine/ptest.c b/crm/pengine/ptest.c index 2c9f74639d..9fff535660 100644 --- a/crm/pengine/ptest.c +++ b/crm/pengine/ptest.c @@ -1,362 +1,362 @@ -/* $Id: ptest.c,v 1.72 2006/02/17 13:22:19 andrew Exp $ */ +/* $Id: ptest.c,v 1.73 2006/03/18 17:23:48 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 #define OPTARGS "V?X:wD:L" #ifdef HAVE_GETOPT_H # include #endif #include #include #include gboolean inhibit_exit = FALSE; extern crm_data_t * do_calculations( pe_working_set_t *data_set, crm_data_t *xml_input, ha_time_t *now); extern void cleanup_calculations(pe_working_set_t *data_set); FILE *dot_strm = NULL; #define DOT_PREFIX "PE_DOT: " /* #define DOT_PREFIX "" */ #define dot_write(fmt...) if(dot_strm != NULL) { \ fprintf(dot_strm, fmt); \ fprintf(dot_strm, "\n"); \ fflush(dot_strm); \ } else { \ crm_debug(DOT_PREFIX""fmt); \ } static void init_dotfile(void) { dot_write("digraph \"g\" {"); dot_write(" size = \"30,30\""); /* dot_write(" graph ["); */ /* dot_write(" fontsize = \"12\""); */ /* dot_write(" fontname = \"Times-Roman\""); */ /* dot_write(" fontcolor = \"black\""); */ /* dot_write(" bb = \"0,0,398.922306,478.927856\""); */ /* dot_write(" color = \"black\""); */ /* dot_write(" ]"); */ /* dot_write(" node ["); */ /* dot_write(" fontsize = \"12\""); */ /* dot_write(" fontname = \"Times-Roman\""); */ /* dot_write(" fontcolor = \"black\""); */ /* dot_write(" shape = \"ellipse\""); */ /* dot_write(" color = \"black\""); */ /* dot_write(" ]"); */ /* dot_write(" edge ["); */ /* dot_write(" fontsize = \"12\""); */ /* dot_write(" fontname = \"Times-Roman\""); */ /* dot_write(" fontcolor = \"black\""); */ /* dot_write(" color = \"black\""); */ /* dot_write(" ]"); */ } static char * create_action_name(action_t *action) { char *action_name = NULL; const char *action_host = NULL; if(action->node) { action_host = action->node->details->uname; action_name = crm_concat(action->uuid, action_host, ' '); } else if(action->pseudo) { action_name = crm_strdup(action->uuid); } else { action_host = ""; action_name = crm_concat(action->uuid, action_host, ' '); } return action_name; } gboolean USE_LIVE_CIB = FALSE; int main(int argc, char **argv) { enum transition_status graph_rc = -1; crm_graph_t *transition = NULL; const char *fake_now = NULL; ha_time_t *a_date = NULL; cib_t * cib_conn = NULL; crm_data_t * cib_object = NULL; int argerr = 0; int flag; char *msg_buffer = NULL; gboolean optional = FALSE; pe_working_set_t data_set; const char *xml_file = NULL; const char *dot_file = NULL; cl_log_set_entity("ptest"); cl_log_set_facility(LOG_USER); set_crm_log_level(LOG_CRIT-1); while (1) { #ifdef HAVE_GETOPT_H int option_index = 0; static struct option long_options[] = { /* Top-level Options */ {F_CRM_DATA, 1, 0, 'X'}, {"live-check", 0, 0, 'L'}, {"help", 0, 0, 0}, {0, 0, 0, 0} }; #endif #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"); break; #endif case 'w': inhibit_exit = TRUE; break; case 'X': xml_file = crm_strdup(optarg); break; case 'D': dot_file = crm_strdup(optarg); break; case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case 'L': USE_LIVE_CIB = TRUE; break; default: printf("?? getopt returned character code 0%o ??\n", flag); ++argerr; break; } } if (optind < argc) { printf("non-option ARGV-elements: "); while (optind < argc) { printf("%s ", argv[optind++]); } printf("\n"); } if (optind > argc) { ++argerr; } if (argerr) { crm_err("%d errors in option parsing", argerr); } crm_info("=#=#=#=#= Getting XML =#=#=#=#="); if(USE_LIVE_CIB) { int rc = cib_ok; cib_conn = cib_new(); rc = cib_conn->cmds->signon( cib_conn, "ptest", cib_command_synchronous); if(rc == cib_ok) { crm_info("Reading XML from: live cluster"); cib_object = get_cib_copy(cib_conn); } else { fprintf(stderr, "Live CIB query failed: %s\n", cib_error2string(rc)); return 3; } if(cib_object == NULL) { fprintf(stderr, "Live CIB query failed: empty result\n"); return 3; } } else if(xml_file != NULL) { FILE *xml_strm = fopen(xml_file, "r"); cib_object = file2xml(xml_strm); } else { cib_object = stdin2xml(); } #ifdef MCHECK mtrace(); #endif - CRM_DEV_ASSERT(cib_object != NULL); + CRM_CHECK(cib_object != NULL, return 4); crm_notice("Required feature set: %s", feature_set(cib_object)); do_id_check(cib_object, NULL); crm_zero_mem_stats(NULL); fake_now = crm_element_value(cib_object, "fake_now"); if(fake_now != NULL) { char *fake_now_copy = crm_strdup(fake_now); char *fake_now_mutable = fake_now_copy; a_date = parse_date(&fake_now_mutable); log_date(LOG_WARNING, "Set fake 'now' to", a_date, ha_log_date|ha_log_time); log_date(LOG_WARNING, "Set fake 'now' to (localtime)", a_date, ha_log_date|ha_log_time|ha_log_local); crm_free(fake_now_copy); } do_calculations(&data_set, cib_object, a_date); msg_buffer = dump_xml_formatted(data_set.graph); fprintf(stdout, "%s\n", msg_buffer); fflush(stdout); crm_free(msg_buffer); dot_strm = fopen(dot_file, "w"); init_dotfile(); slist_iter( action, action_t, data_set.actions, lpc, char *action_name = create_action_name(action); crm_debug_3("Action %d: %p", action->id, action); if(action->dumped == FALSE) { if(action->rsc != NULL && action->rsc->is_managed == FALSE) { dot_write("\"%s\" [ font_color=black style=filled fillcolor=%s ]", action_name, "purple"); } else if(action->optional) { dot_write("\"%s\" [ style=\"dashed\" color=\"%s\" fontcolor=\"%s\" ]", action_name, "blue", action->pseudo?"orange":"black"); } else { dot_write("\"%s\" [ font_color=purple style=filled fillcolor=%s ]", action_name, "red"); - CRM_DEV_ASSERT(action->runnable == FALSE); + CRM_CHECK(action->runnable == FALSE, ;); } } else { dot_write("\"%s\" [ style=bold color=\"%s\" fontcolor=\"%s\" ]", action_name, "green", action->pseudo?"orange":"black"); } crm_free(action_name); ); slist_iter( action, action_t, data_set.actions, lpc, int last_action = -1; slist_iter( before, action_wrapper_t, action->actions_before, lpc2, char *before_name = NULL; char *after_name = NULL; optional = FALSE; if(last_action == before->action->id) { continue; } last_action = before->action->id; if(action->dumped && before->action->dumped) { } else if(action->optional || before->action->optional) { optional = TRUE; } before_name = create_action_name(before->action); after_name = create_action_name(action); dot_write("\"%s\" -> \"%s\" [ style = %s]", before_name, after_name, optional?"dashed":"bold"); crm_free(before_name); crm_free(after_name); ); ); dot_write("}"); transition = unpack_graph(data_set.graph); print_graph(LOG_NOTICE, transition); do { graph_rc = run_graph(transition); } while(graph_rc == transition_active); if(graph_rc != transition_complete) { crm_crit("Transition failed: %s", transition_status(graph_rc)); print_graph(LOG_ERR, transition); } data_set.input = NULL; cleanup_calculations(&data_set); destroy_graph(transition); crm_mem_stats(NULL); - CRM_DEV_ASSERT(crm_mem_stats(NULL) == FALSE); - CRM_DEV_ASSERT(graph_rc == transition_complete); + CRM_CHECK(crm_mem_stats(NULL) == FALSE, crm_err("Memory leak detected")); + CRM_CHECK(graph_rc == transition_complete, crm_err("An invalid transition was produced")); crm_free(cib_object); #ifdef MCHECK muntrace(); #endif /* required for MallocDebug.app */ if(inhibit_exit) { GMainLoop* mainloop = g_main_new(FALSE); g_main_run(mainloop); } return 0; } diff --git a/crm/pengine/rules.c b/crm/pengine/rules.c index 1594dc16db..ae9a91b696 100644 --- a/crm/pengine/rules.c +++ b/crm/pengine/rules.c @@ -1,468 +1,468 @@ -/* $Id: rules.c,v 1.21 2005/12/19 16:54:44 andrew Exp $ */ +/* $Id: rules.c,v 1.22 2006/03/18 17:23:48 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 ha_time_t *parse_xml_duration(ha_time_t *start, crm_data_t *duration_spec); gboolean test_date_expression(crm_data_t *time_expr, pe_working_set_t *data_set); gboolean cron_range_satisfied(ha_time_t *now, crm_data_t *cron_spec); gboolean test_attr_expression( crm_data_t *expr, GHashTable *hash, pe_working_set_t *data_set); gboolean test_role_expression( crm_data_t *expr, resource_t *rsc, pe_working_set_t *data_set); gboolean test_ruleset(crm_data_t *ruleset, node_t *node, pe_working_set_t *data_set) { gboolean ruleset_default = TRUE; xml_child_iter_filter( ruleset, rule, XML_TAG_RULE, ruleset_default = FALSE; if(test_rule(rule, node, NULL, data_set)) { return TRUE; } ); return ruleset_default; } gboolean test_rule(crm_data_t *rule, node_t *node, resource_t *rsc, pe_working_set_t *data_set) { gboolean test = TRUE; gboolean passed = TRUE; gboolean do_and = TRUE; const char *value = crm_element_value(rule, "boolean_op"); if(safe_str_eq(value, "or")) { do_and = FALSE; passed = FALSE; } crm_debug_2("Testing rule %s", ID(rule)); xml_child_iter( rule, expr, test = test_expression(expr, node, rsc, data_set); if(test && do_and == FALSE) { crm_debug_3("Expression %s/%s passed", ID(rule), ID(expr)); return TRUE; } else if(test == FALSE && do_and) { crm_debug_3("Expression %s/%s failed", ID(rule), ID(expr)); return FALSE; } ); crm_debug_2("Rule %s %s", ID(rule), passed?"passed":"failed"); return passed; } gboolean test_expression(crm_data_t *expr, node_t *node, resource_t *rsc, pe_working_set_t *data_set) { gboolean accept = FALSE; switch(find_expression_type(expr)) { case nested_rule: accept = test_rule(expr, node, rsc, data_set); break; case attr_expr: case loc_expr: /* these expressions can never succeed if there is * no node to compare with */ if(node != NULL) { accept = test_attr_expression( expr, node->details->attrs, data_set); } break; case time_expr: accept = test_date_expression(expr, data_set); break; case role_expr: if(rsc != NULL) { accept = test_role_expression(expr, rsc, data_set); } break; default: - CRM_DEV_ASSERT(FALSE /* bad type */); + CRM_CHECK(FALSE /* bad type */, return FALSE); accept = FALSE; } crm_debug_2("Expression %s %s", ID(expr), accept?"passed":"failed"); return accept; } enum expression_type find_expression_type(crm_data_t *expr) { const char *tag = NULL; const char *attr = NULL; attr = crm_element_value(expr, XML_EXPR_ATTR_ATTRIBUTE); tag = crm_element_name(expr); if(safe_str_eq(tag, "date_expression")) { return time_expr; } else if(safe_str_eq(tag, XML_TAG_RULE)) { return nested_rule; } else if(safe_str_neq(tag, "expression")) { return not_expr; } else if(safe_str_eq(attr, "#uname") || safe_str_eq(attr, "#id")) { return loc_expr; } else if(safe_str_eq(attr, "#role")) { return role_expr; } return attr_expr; } gboolean test_role_expression( crm_data_t *expr, resource_t *rsc, pe_working_set_t *data_set) { gboolean accept = FALSE; const char *op = NULL; const char *value = NULL; if(rsc == NULL) { return accept; } value = crm_element_value(expr, XML_EXPR_ATTR_VALUE); op = crm_element_value(expr, XML_EXPR_ATTR_OPERATION); if(safe_str_eq(op, "defined")) { if(rsc->next_role > RSC_ROLE_STARTED) { accept = TRUE; } } else if(safe_str_eq(op, "not_defined")) { if(rsc->next_role < RSC_ROLE_SLAVE && rsc->next_role > RSC_ROLE_UNKNOWN) { accept = TRUE; } } else if(safe_str_eq(op, "eq")) { if(text2role(value) == rsc->next_role) { accept = TRUE; } } else if(safe_str_eq(op, "ne")) { /* we will only test "ne" wtih master/slave roles style */ if(rsc->next_role < RSC_ROLE_SLAVE && rsc->next_role > RSC_ROLE_UNKNOWN) { accept = FALSE; } else if(text2role(value) != rsc->next_role) { accept = TRUE; } } return accept; } gboolean test_attr_expression(crm_data_t *expr, GHashTable *hash, pe_working_set_t *data_set) { gboolean accept = FALSE; int cmp = 0; const char *h_val = NULL; const char *op = NULL; const char *type = NULL; const char *attr = NULL; const char *value = NULL; attr = crm_element_value(expr, XML_EXPR_ATTR_ATTRIBUTE); op = crm_element_value(expr, XML_EXPR_ATTR_OPERATION); value = crm_element_value(expr, XML_EXPR_ATTR_VALUE); type = crm_element_value(expr, XML_EXPR_ATTR_TYPE); if(attr == NULL || op == NULL) { pe_err("Invlaid attribute or operation in expression" " (\'%s\' \'%s\' \'%s\')", crm_str(attr), crm_str(op), crm_str(value)); return FALSE; } if(hash != NULL) { h_val = (const char*)g_hash_table_lookup(hash, attr); } if(value != NULL && h_val != NULL) { if(type == NULL || (safe_str_eq(type, "string"))) { cmp = strcmp(h_val, value); } else if(safe_str_eq(type, "number")) { int h_val_f = crm_parse_int(h_val, NULL); int value_f = crm_parse_int(value, NULL); if(h_val_f < value_f) { cmp = -1; } else if(h_val_f > value_f) { cmp = 1; } else { cmp = 0; } } else if(safe_str_eq(type, "version")) { cmp = compare_version(h_val, value); } } else if(value == NULL && h_val == NULL) { cmp = 0; } else if(value == NULL) { cmp = 1; } else { cmp = -1; } if(safe_str_eq(op, "defined")) { if(h_val != NULL) { accept = TRUE; } } else if(safe_str_eq(op, "not_defined")) { if(h_val == NULL) { accept = TRUE; } } else if(safe_str_eq(op, "eq")) { if((h_val == value) || cmp == 0) { accept = TRUE; } } else if(safe_str_eq(op, "ne")) { if((h_val == NULL && value != NULL) || (h_val != NULL && value == NULL) || cmp != 0) { accept = TRUE; } } else if(value == NULL || h_val == NULL) { /* the comparision is meaningless from this point on */ accept = FALSE; } else if(safe_str_eq(op, "lt")) { if(cmp < 0) { accept = TRUE; } } else if(safe_str_eq(op, "lte")) { if(cmp <= 0) { accept = TRUE; } } else if(safe_str_eq(op, "gt")) { if(cmp > 0) { accept = TRUE; } } else if(safe_str_eq(op, "gte")) { if(cmp >= 0) { accept = TRUE; } } return accept; } /* As per the nethack rules: * * moon period = 29.53058 days ~= 30, year = 365.2422 days * days moon phase advances on first day of year compared to preceding year * = 365.2422 - 12*29.53058 ~= 11 * years in Metonic cycle (time until same phases fall on the same days of * the month) = 18.6 ~= 19 * moon phase on first day of year (epact) ~= (11*(year%19) + 29) % 30 * (29 as initial condition) * current phase in days = first day phase + days elapsed in year * 6 moons ~= 177 days * 177 ~= 8 reported phases * 22 * + 11/22 for rounding * * 0-7, with 0: new, 4: full */ static int phase_of_the_moon(ha_time_t *now) { int epact, diy, goldn; diy = now->yeardays; goldn = (now->years % 19) + 1; epact = (11 * goldn + 18) % 30; if ((epact == 25 && goldn > 11) || epact == 24) epact++; return( (((((diy + epact) * 6) + 11) % 177) / 22) & 7 ); } #define cron_check(xml_field, time_field) \ value = crm_element_value(cron_spec, xml_field); \ if(value != NULL) { \ decodeNVpair(value, '-', &value_low, &value_high); \ - CRM_DEV_ASSERT(value_low != NULL); \ - value_low_i = crm_parse_int(value_low, "0"); \ + CRM_CHECK(value_low != NULL, return FALSE); \ + value_low_i = crm_parse_int(value_low, "0"); \ value_high_i = crm_parse_int(value_high, "-1"); \ if(value_low_i > time_field) { \ return FALSE; \ } else if(value_high_i < 0) { \ } else if(value_high_i < time_field) { \ return FALSE; \ } \ } gboolean cron_range_satisfied(ha_time_t *now, crm_data_t *cron_spec) { const char *value = NULL; char *value_low = NULL; char *value_high = NULL; int value_low_i = 0; int value_high_i = 0; cron_check("seconds", now->seconds); cron_check("minutes", now->minutes); cron_check("hours", now->hours); cron_check("monthdays", now->days); cron_check("weekdays", now->weekdays); cron_check("yeardays", now->yeardays); cron_check("weeks", now->weeks); cron_check("months", now->months); cron_check("years", now->years); cron_check("weekyears", now->weekyears); cron_check("moon", phase_of_the_moon(now)); return TRUE; } #define update_field(xml_field, time_fn) \ value = crm_element_value(duration_spec, xml_field); \ if(value != NULL) { \ int value_i = crm_parse_int(value, "0"); \ time_fn(end, value_i); \ } ha_time_t * parse_xml_duration(ha_time_t *start, crm_data_t *duration_spec) { ha_time_t *end = NULL; const char *value = NULL; end = new_ha_date(FALSE); ha_set_time(end, start, TRUE); update_field("years", add_years); update_field("months", add_months); update_field("weeks", add_weeks); update_field("days", add_days); update_field("hours", add_hours); update_field("minutes", add_minutes); update_field("seconds", add_seconds); return end; } gboolean test_date_expression(crm_data_t *time_expr, pe_working_set_t *data_set) { ha_time_t *start = NULL; ha_time_t *end = NULL; const char *value = NULL; char *value_copy = NULL; char *value_copy_start = NULL; const char *op = crm_element_value(time_expr, "operation"); crm_data_t *duration_spec = NULL; crm_data_t *date_spec = NULL; gboolean passed = FALSE; crm_debug_2("Testing expression: %s", ID(time_expr)); duration_spec = cl_get_struct(time_expr, "duration"); date_spec = cl_get_struct(time_expr, "date_spec"); value = crm_element_value(time_expr, "start"); if(value != NULL) { value_copy = crm_strdup(value); value_copy_start = value_copy; start = parse_date(&value_copy); crm_free(value_copy_start); } value = crm_element_value(time_expr, "end"); if(value != NULL) { value_copy = crm_strdup(value); value_copy_start = value_copy; end = parse_date(&value_copy); crm_free(value_copy_start); } if(start != NULL && end == NULL) { end = parse_xml_duration(start, duration_spec); } if(op == NULL) { op = "in_range"; } if(safe_str_eq(op, "date_spec") || safe_str_eq(op, "in_range")) { if(start != NULL && compare_date(start, data_set->now) > 0) { passed = FALSE; } else if(end != NULL && compare_date(end, data_set->now) < 0) { passed = FALSE; } else if(safe_str_eq(op, "in_range")) { passed = TRUE; } else { passed = cron_range_satisfied(data_set->now, date_spec); } } else if(safe_str_eq(op, "gt") && compare_date(start, data_set->now) < 0) { passed = TRUE; } else if(safe_str_eq(op, "lt") && compare_date(end, data_set->now) > 0) { passed = TRUE; } else if(safe_str_eq(op, "eq") && compare_date(start, data_set->now) == 0) { passed = TRUE; } else if(safe_str_eq(op, "neq") && compare_date(start, data_set->now) != 0) { passed = TRUE; } free_ha_date(start); free_ha_date(end); return passed; } diff --git a/crm/pengine/testcases/orphan-1.exp b/crm/pengine/testcases/orphan-1.exp index dbf3f17c97..920912cadc 100644 --- a/crm/pengine/testcases/orphan-1.exp +++ b/crm/pengine/testcases/orphan-1.exp @@ -1,276 +1,276 @@ - + - + diff --git a/crm/pengine/unpack.c b/crm/pengine/unpack.c index 753b1b6303..c8ce9b79e8 100644 --- a/crm/pengine/unpack.c +++ b/crm/pengine/unpack.c @@ -1,2038 +1,2017 @@ -/* $Id: unpack.c,v 1.165 2006/03/17 00:43:29 andrew Exp $ */ +/* $Id: unpack.c,v 1.166 2006/03/18 17:23:48 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 /* for ONLINESTATUS */ #include #include #include gint sort_op_by_callid(gconstpointer a, gconstpointer b); gboolean unpack_rsc_to_attr(crm_data_t *xml_obj, pe_working_set_t *data_set); gboolean unpack_rsc_to_node(crm_data_t *xml_obj, pe_working_set_t *data_set); gboolean unpack_rsc_order(crm_data_t *xml_obj, pe_working_set_t *data_set); gboolean unpack_rsc_colocation(crm_data_t *xml_obj, pe_working_set_t *data_set); gboolean unpack_rsc_location(crm_data_t *xml_obj, pe_working_set_t *data_set); gboolean unpack_lrm_resources( node_t *node, crm_data_t * lrm_state, pe_working_set_t *data_set); gboolean add_node_attrs( crm_data_t * attrs, node_t *node, pe_working_set_t *data_set); gboolean unpack_rsc_op( resource_t *rsc, node_t *node, crm_data_t *xml_op, int *max_call_id, enum action_fail_response *failed, pe_working_set_t *data_set); gboolean determine_online_status( crm_data_t * node_state, node_t *this_node, pe_working_set_t *data_set); gboolean rsc_colocation_new( const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh, const char *state_lh, const char *state_rh); gboolean create_ordering( const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh, pe_working_set_t *data_set); const char *param_value( GHashTable *hash, crm_data_t * parent, const char *name); rsc_to_node_t *generate_location_rule( resource_t *rsc, crm_data_t *location_rule, pe_working_set_t *data_set); #define get_cluster_pref(pref) value = g_hash_table_lookup(config_hash, pref); \ if(value == NULL) { \ pe_config_warn("No value specified for cluster preference: %s", pref); \ } gboolean unpack_config(crm_data_t * config, pe_working_set_t *data_set) { /* const char *attr_filter[] = { */ /* "default_resource_stickiness", */ /* "transition_idle_timeout", */ /* "stonith_enabled", */ /* "symmetric_cluster" */ /* }; */ const char *value = NULL; GHashTable *config_hash = g_hash_table_new_full( g_str_hash,g_str_equal, g_hash_destroy_str,g_hash_destroy_str); data_set->config_hash = config_hash; unpack_instance_attributes( config, "cluster_property_set", NULL, config_hash, NULL, 0, data_set); #if CRM_DEPRECATED_SINCE_2_0_1 param_value(config_hash, config, "transition_idle_timeout"); param_value(config_hash, config, "default_resource_stickiness"); param_value(config_hash, config, "default_resource_failure_stickiness"); param_value(config_hash, config, "stonith_enabled"); param_value(config_hash, config, "symmetric_cluster"); param_value(config_hash, config, "no_quorum_policy"); param_value(config_hash, config, "stop_orphan_resources"); param_value(config_hash, config, "stop_orphan_actions"); param_value(config_hash, config, "remove_after_stop"); param_value(config_hash, config, "is_managed_default"); param_value(config_hash, config, "short_resource_names"); param_value(config_hash, config, "stonith_action"); #endif get_cluster_pref("transition_idle_timeout"); if(value != NULL) { long tmp = crm_get_msec(value); if(tmp > 0) { crm_free(data_set->transition_idle_timeout); data_set->transition_idle_timeout = crm_strdup(value); } else { crm_err("Invalid value for transition_idle_timeout: %s", value); } } crm_debug("%s set to: %s", "transition_idle_timeout", data_set->transition_idle_timeout); get_cluster_pref("default_resource_stickiness"); data_set->default_resource_stickiness = char2score(value); crm_info("Default stickiness: %d", data_set->default_resource_stickiness); get_cluster_pref("default_resource_failure_stickiness"); data_set->default_resource_fail_stickiness = char2score(value); crm_info("Default failure stickiness: %d", data_set->default_resource_fail_stickiness); get_cluster_pref("stonith_enabled"); if(value != NULL) { cl_str_to_boolean(value, &data_set->stonith_enabled); } crm_info("STONITH of failed nodes is %s", data_set->stonith_enabled?"enabled":"disabled"); get_cluster_pref("stonith_action"); if(value == NULL || safe_str_neq(value, "poweroff")) { value = "reboot"; } data_set->stonith_action = value; crm_info("STONITH will %s nodes", data_set->stonith_action); get_cluster_pref("symmetric_cluster"); if(value != NULL) { cl_str_to_boolean(value, &data_set->symmetric_cluster); } if(data_set->symmetric_cluster) { crm_info("Cluster is symmetric" " - resources can run anywhere by default"); } get_cluster_pref("short_resource_names"); if(value != NULL) { cl_str_to_boolean(value, &data_set->short_rsc_names); } crm_info("Using short resource names: %s", data_set->short_rsc_names?"true":"false"); get_cluster_pref("no_quorum_policy"); if(safe_str_eq(value, "ignore")) { data_set->no_quorum_policy = no_quorum_ignore; } else if(safe_str_eq(value, "freeze")) { data_set->no_quorum_policy = no_quorum_freeze; } else { data_set->no_quorum_policy = no_quorum_stop; } switch (data_set->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_notice("On loss of CCM Quorum: Ignore"); break; } get_cluster_pref("stop_orphan_resources"); if(value != NULL) { cl_str_to_boolean(value, &data_set->stop_rsc_orphans); } crm_info("Orphan resources are %s", data_set->stop_rsc_orphans?"stopped":"ignored"); get_cluster_pref("stop_orphan_actions"); if(value != NULL) { cl_str_to_boolean(value, &data_set->stop_action_orphans); } crm_info("Orphan resource actions are %s", data_set->stop_action_orphans?"stopped":"ignored"); get_cluster_pref("remove_after_stop"); if(value != NULL) { cl_str_to_boolean(value, &data_set->remove_after_stop); } crm_info("Stopped resources are removed from the status section: %s", data_set->remove_after_stop?"true":"false"); get_cluster_pref("is_managed_default"); if(value != NULL) { cl_str_to_boolean(value, &data_set->is_managed_default); } crm_info("By default resources are %smanaged", data_set->is_managed_default?"":"not "); return TRUE; } const char * param_value(GHashTable *hash, crm_data_t * parent, const char *name) { const char *value = NULL; const char *pref_name = NULL; crm_data_t * a_default = NULL; if(parent != NULL) { crm_validate_data(parent); xml_child_iter_filter( parent, a_child, XML_CIB_TAG_NVPAIR, pref_name = crm_element_value(a_child, XML_NVPAIR_ATTR_NAME); if(safe_str_eq(name, pref_name)) { a_default = a_child; break; } ); } if(a_default == NULL) { return NULL; } value = crm_element_value(a_default, XML_NVPAIR_ATTR_VALUE); if(value && hash) { if(g_hash_table_lookup(hash, name) == NULL) { g_hash_table_insert( hash, crm_strdup(name), crm_strdup(value)); } } return value; } gboolean unpack_nodes(crm_data_t * xml_nodes, pe_working_set_t *data_set) { node_t *new_node = NULL; const char *id = NULL; const char *uname = NULL; const char *type = NULL; crm_debug_2("Begining unpack... %s", xml_nodes?crm_element_name(xml_nodes):""); xml_child_iter_filter( 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_debug_3("Processing node %s/%s", uname, id); if(id == NULL) { pe_config_err("Must specify id tag in "); continue; } if(type == NULL) { pe_config_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_debug_3("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->attrs = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); /* if(data_set->have_quorum == FALSE */ /* && data_set->no_quorum_policy == no_quorum_stop) { */ /* /\* start shutting resources down *\/ */ /* new_node->weight = -INFINITY; */ /* } */ if(data_set->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(type == NULL || safe_str_eq(type, "member") || safe_str_eq(type, NORMALNODE)) { new_node->details->type = node_member; } add_node_attrs(xml_obj, new_node, data_set); 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; new_node->details->standby = TRUE; } data_set->nodes = g_list_append(data_set->nodes, new_node); crm_debug_3("Done with node %s", crm_element_value(xml_obj, XML_ATTR_UNAME)); crm_action_debug_3(print_node("Added", new_node, FALSE)); ); /* data_set->nodes = g_list_sort(data_set->nodes, sort_node_weight); */ return TRUE; } gboolean unpack_resources(crm_data_t * xml_resources, pe_working_set_t *data_set) { crm_debug_2("Begining unpack... %s", xml_resources?crm_element_name(xml_resources):""); xml_child_iter( xml_resources, xml_obj, resource_t *new_rsc = NULL; crm_debug_2("Begining unpack... %s", xml_obj?crm_element_name(xml_obj):""); if(common_unpack(xml_obj, &new_rsc, NULL, data_set)) { data_set->resources = g_list_append( data_set->resources, new_rsc); print_resource(LOG_DEBUG_3, "Added", new_rsc, FALSE); } else { pe_config_err("Failed unpacking %s %s", crm_element_name(xml_obj), crm_element_value(xml_obj, XML_ATTR_ID)); } ); data_set->resources = g_list_sort( data_set->resources, sort_rsc_priority); return TRUE; } gboolean unpack_constraints(crm_data_t * xml_constraints, pe_working_set_t *data_set) { crm_data_t *lifetime = NULL; crm_debug_2("Begining unpack... %s", xml_constraints?crm_element_name(xml_constraints):""); xml_child_iter( xml_constraints, xml_obj, const char *id = crm_element_value(xml_obj, XML_ATTR_ID); if(id == NULL) { pe_config_err("Constraint <%s...> must have an id", crm_element_name(xml_obj)); continue; } crm_debug_3("Processing constraint %s %s", crm_element_name(xml_obj),id); lifetime = cl_get_struct(xml_obj, "lifetime"); if(test_ruleset(lifetime, NULL, data_set) == FALSE) { crm_info("Constraint %s %s is not active", crm_element_name(xml_obj), id); } else if(safe_str_eq(XML_CONS_TAG_RSC_ORDER, crm_element_name(xml_obj))) { unpack_rsc_order(xml_obj, data_set); } else if(safe_str_eq(XML_CONS_TAG_RSC_DEPEND, crm_element_name(xml_obj))) { unpack_rsc_colocation(xml_obj, data_set); } else if(safe_str_eq(XML_CONS_TAG_RSC_LOCATION, crm_element_name(xml_obj))) { unpack_rsc_location(xml_obj, data_set); } else { pe_err("Unsupported constraint type: %s", crm_element_name(xml_obj)); } ); return TRUE; } /* remove nodes that are down, stopping */ /* create +ve rsc_to_node constraints between resources and the nodes they are running on */ /* anything else? */ gboolean unpack_status(crm_data_t * status, pe_working_set_t *data_set) { const char *id = NULL; const char *uname = NULL; crm_data_t * lrm_rsc = NULL; crm_data_t * attrs = NULL; node_t *this_node = NULL; crm_debug_3("Begining unpack"); xml_child_iter_filter( 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_TAG_TRANSIENT_NODEATTRS, FALSE); lrm_rsc = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE); lrm_rsc = find_xml_node(lrm_rsc, XML_LRM_TAG_RESOURCES, FALSE); crm_debug_3("Processing node %s", uname); this_node = pe_find_node_id(data_set->nodes, id); if(uname == NULL) { /* error */ continue; } else if(this_node == NULL) { pe_config_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_debug_3("Adding runtime node attrs"); add_node_attrs(attrs, this_node, data_set); crm_debug_3("determining node state"); determine_online_status(node_state, this_node, data_set); if(this_node->details->online || data_set->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_debug_3("Processing lrm resource entries"); unpack_lrm_resources(this_node, lrm_rsc, data_set); } ); return TRUE; } static gboolean determine_online_status_no_fencing(crm_data_t * node_state, node_t *this_node) { gboolean online = FALSE; 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 *exp_state = crm_element_value(node_state, XML_CIB_ATTR_EXPSTATE); if(!crm_is_true(ccm_state) || safe_str_eq(ha_state,DEADSTATUS)){ crm_debug_2("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_2("CRMd is down: ha_state=%s, ccm_state=%s", crm_str(ha_state), crm_str(ccm_state)); crm_debug_2("\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_warn("Node %s is partially & un-expectedly down", this_node->details->uname); crm_info("\tha_state=%s, ccm_state=%s," " crm_state=%s, join_state=%s, expected=%s", crm_str(ha_state), crm_str(ccm_state), crm_str(crm_state), crm_str(join_state), crm_str(exp_state)); } return online; } static gboolean determine_online_status_fencing(crm_data_t * node_state, node_t *this_node) { gboolean online = FALSE; 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 *exp_state = crm_element_value(node_state, XML_CIB_ATTR_EXPSTATE); if(crm_is_true(ccm_state) && (ha_state == NULL || safe_str_eq(ha_state, ACTIVESTATUS)) && safe_str_eq(crm_state, ONLINESTATUS) && safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER)) { online = TRUE; } else if(crm_is_true(ccm_state) == FALSE /* && safe_str_eq(ha_state, DEADSTATUS) */ && safe_str_eq(crm_state, OFFLINESTATUS) && this_node->details->expected_up == FALSE) { crm_debug("Node %s is down: join_state=%s, expected=%s", this_node->details->uname, crm_str(join_state), crm_str(exp_state)); } else if(this_node->details->expected_up == FALSE) { crm_info("Node %s is comming up", this_node->details->uname); crm_debug("\tha_state=%s, ccm_state=%s," " crm_state=%s, join_state=%s, expected=%s", crm_str(ha_state), crm_str(ccm_state), crm_str(crm_state), crm_str(join_state), crm_str(exp_state)); } else { /* mark it unclean */ this_node->details->unclean = TRUE; crm_warn("Node %s (%s)is un-expectedly down", this_node->details->uname, this_node->details->id); crm_info("\tha_state=%s, ccm_state=%s," " crm_state=%s, join_state=%s, expected=%s", crm_str(ha_state), crm_str(ccm_state), crm_str(crm_state), crm_str(join_state), crm_str(exp_state)); } return online; } gboolean determine_online_status( crm_data_t * node_state, node_t *this_node, pe_working_set_t *data_set) { int shutdown = 0; gboolean online = FALSE; const char *exp_state = crm_element_value(node_state, XML_CIB_ATTR_EXPSTATE); if(this_node == NULL) { pe_config_err("No node to check"); return online; } ha_msg_value_int(node_state, XML_CIB_ATTR_SHUTDOWN, &shutdown); this_node->details->expected_up = FALSE; if(safe_str_eq(exp_state, CRMD_JOINSTATE_MEMBER)) { this_node->details->expected_up = TRUE; } this_node->details->shutdown = FALSE; if(shutdown != 0) { this_node->details->shutdown = TRUE; this_node->details->expected_up = FALSE; } if(data_set->stonith_enabled == FALSE) { online = determine_online_status_no_fencing( node_state, this_node); } else { online = determine_online_status_fencing( node_state, this_node); } if(online) { crm_debug_2("Node %s is online", this_node->details->uname); this_node->details->online = TRUE; } else { /* remove node from contention */ this_node->fixed = TRUE; this_node->weight = -INFINITY; crm_debug_2("Node %s is down", this_node->details->uname); } if(online && this_node->details->shutdown) { /* dont run resources here */ this_node->fixed = TRUE; this_node->weight = -INFINITY; crm_debug_2("Node %s is due for shutdown", this_node->details->uname); } if(this_node->details->unclean) { pe_proc_warn("Node %s is unclean", this_node->details->uname); } return online; } #define set_char(x) last_rsc_id[len] = x; complete = TRUE; static void increment_clone(char *last_rsc_id) { gboolean complete = FALSE; int len = 0; - CRM_DEV_ASSERT(last_rsc_id != NULL); + CRM_CHECK(last_rsc_id != NULL, return); if(last_rsc_id != NULL) { len = strlen(last_rsc_id); } len--; while(complete == FALSE && len > 0) { switch (last_rsc_id[len]) { case 0: len--; break; case '0': set_char('1'); break; case '1': set_char('2'); break; case '2': set_char('3'); break; case '3': set_char('4'); break; case '4': set_char('5'); break; case '5': set_char('6'); break; case '6': set_char('7'); break; case '7': set_char('8'); break; case '8': set_char('9'); break; case '9': last_rsc_id[len] = '0'; len--; break; default: crm_err("Unexpected char: %c (%d)", last_rsc_id[len], len); break; } } } extern gboolean DeleteRsc(resource_t *rsc, node_t *node, pe_working_set_t *data_set); static resource_t * unpack_find_resource( pe_working_set_t *data_set, node_t *node, const char *rsc_id) { resource_t *rsc = NULL; gboolean is_duped_clone = FALSE; char *alt_rsc_id = crm_strdup(rsc_id); while(rsc == NULL) { crm_debug_3("looking for: %s", alt_rsc_id); rsc = pe_find_resource(data_set->resources, alt_rsc_id); /* no match */ if(rsc == NULL) { crm_debug_3("not found"); break; /* not running anywhere else */ } else if(rsc->running_on == NULL) { crm_debug_3("not active yet"); break; /* always unique */ } else if(rsc->globally_unique) { crm_debug_3("unique"); break; /* running somewhere already but we dont care * find another clone instead */ } else { crm_debug_2("find another one"); rsc = NULL; is_duped_clone = TRUE; increment_clone(alt_rsc_id); } } crm_free(alt_rsc_id); if(is_duped_clone && rsc != NULL) { crm_info("Internally renamed %s on %s to %s", rsc_id, node->details->uname, rsc->id); rsc->name = rsc_id; } return rsc; } static resource_t * process_orphan_resource(crm_data_t *rsc_entry, node_t *node, pe_working_set_t *data_set) { resource_t *rsc = NULL; gboolean is_duped_clone = FALSE; const char *rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID); crm_data_t *xml_rsc = create_xml_node(NULL, XML_CIB_TAG_RESOURCE); crm_log_xml_info(rsc_entry, "Orphan resource"); pe_config_warn("Nothing known about resource %s running on %s", rsc_id, node->details->uname); if(pe_find_resource(data_set->resources, rsc_id) != NULL) { is_duped_clone = TRUE; } copy_in_properties(xml_rsc, rsc_entry); common_unpack(xml_rsc, &rsc, NULL, data_set); rsc->orphan = TRUE; data_set->resources = g_list_append(data_set->resources, rsc); if(data_set->stop_rsc_orphans == FALSE && is_duped_clone == FALSE) { rsc->is_managed = FALSE; } else { crm_info("Making sure orphan %s is stopped", rsc_id); print_resource(LOG_DEBUG_3, "Added orphan", rsc, FALSE); - CRM_DEV_ASSERT(rsc != NULL); + CRM_CHECK(rsc != NULL, return NULL); slist_iter( any_node, node_t, data_set->nodes, lpc, rsc2node_new( "__orphan_dont_run__", rsc, -INFINITY, any_node, data_set); ); } return rsc; } static gboolean check_rsc_parameters(resource_t *rsc, node_t *node, crm_data_t *rsc_entry, pe_working_set_t *data_set) { int attr_lpc = 0; gboolean force_restart = FALSE; gboolean delete_resource = FALSE; const char *value = NULL; const char *old_value = NULL; const char *attr_list[] = { XML_ATTR_TYPE, XML_AGENT_ATTR_CLASS, XML_AGENT_ATTR_PROVIDER }; for(; attr_lpc < DIMOF(attr_list); attr_lpc++) { value = crm_element_value(rsc->xml, attr_list[attr_lpc]); old_value = crm_element_value(rsc_entry, attr_list[attr_lpc]); if(safe_str_eq(value, old_value)) { continue; } force_restart = TRUE; crm_notice("Forcing restart of %s on %s, %s changed: %s -> %s", rsc->id, node->details->uname, attr_list[attr_lpc], crm_str(old_value), crm_str(value)); } if(force_restart) { /* make sure the restart happens */ stop_action(rsc, node, FALSE); rsc->start_pending = TRUE; delete_resource = TRUE; } return delete_resource; } static void process_rsc_state(resource_t *rsc, node_t *node, enum action_fail_response on_fail, pe_working_set_t *data_set) { crm_debug_2("Resource %s is %s on %s", rsc->id, role2text(rsc->role), node->details->uname); rsc->known_on = g_list_append(rsc->known_on, node); if(rsc->role != RSC_ROLE_STOPPED) { if(on_fail != action_fail_ignore) { rsc->failed = TRUE; crm_debug_2("Force stop"); } crm_debug_2("Adding %s to %s", rsc->id, node->details->uname); native_add_running(rsc, node, data_set); if(on_fail == action_fail_ignore) { /* nothing to do */ } else if(node->details->unclean) { stop_action(rsc, node, FALSE); } else if(on_fail == action_fail_fence) { /* treat it as if it is still running * but also mark the node as unclean */ node->details->unclean = TRUE; stop_action(rsc, node, FALSE); } else if(on_fail == action_fail_block) { /* is_managed == FALSE will prevent any * actions being sent for the resource */ rsc->is_managed = FALSE; } else if(on_fail == action_fail_migrate) { stop_action(rsc, node, FALSE); /* make sure it comes up somewhere else * or not at all */ rsc2node_new("__action_migration_auto__", rsc, -INFINITY, node, data_set); } else { stop_action(rsc, node, FALSE); } } else { char *key = stop_key(rsc); GListPtr possible_matches = find_actions(rsc->actions, key, node); slist_iter(stop, action_t, possible_matches, lpc, stop->optional = TRUE; ); crm_free(key); /* if(rsc->failed == FALSE && node->details->online) { */ /* delete_resource = TRUE; */ /* } */ } } static void unpack_lrm_rsc_state( node_t *node, crm_data_t * rsc_entry, pe_working_set_t *data_set) { int fail_count = 0; char *fail_attr = NULL; const char *fail_val = NULL; gboolean delete_resource = FALSE; const char *rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID); const char *rsc_state = crm_element_value(rsc_entry, XML_LRM_ATTR_RSCSTATE); int max_call_id = -1; GListPtr op_list = NULL; GListPtr sorted_op_list = NULL; enum action_fail_response on_fail = FALSE; enum rsc_role_e saved_role = RSC_ROLE_UNKNOWN; resource_t *rsc = unpack_find_resource(data_set, node, rsc_id); crm_debug_3("[%s] Processing %s on %s (%s)", crm_element_name(rsc_entry), rsc_id, node->details->uname, rsc_state); if(rsc == NULL) { rsc = process_orphan_resource(rsc_entry, node, data_set); } CRM_ASSERT(rsc != NULL); delete_resource = check_rsc_parameters(rsc, node, rsc_entry, data_set); /* process failure stickiness */ fail_count = 0; fail_attr = crm_concat("fail-count", rsc->id, '-'); fail_val = g_hash_table_lookup(node->details->attrs, fail_attr); if(fail_val != NULL) { crm_debug("%s: %s", fail_attr, fail_val); fail_count = crm_parse_int(fail_val, "0"); } crm_free(fail_attr); if(fail_count > 0 && rsc->fail_stickiness != 0) { rsc2node_new("fail_stickiness", rsc, fail_count * rsc->fail_stickiness, node, data_set); crm_debug("Setting failure stickiness for %s on %s: %d", rsc->id, node->details->uname, fail_count * rsc->fail_stickiness); } /* process operations */ max_call_id = -1; op_list = NULL; sorted_op_list = NULL; xml_child_iter_filter( rsc_entry, rsc_op, XML_LRM_TAG_RSC_OP, op_list = g_list_append(op_list, rsc_op); ); if(op_list != NULL) { saved_role = rsc->role; on_fail = action_fail_ignore; rsc->role = RSC_ROLE_STOPPED; 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, &max_call_id, &on_fail, data_set); ); /* no need to free the contents */ g_list_free(sorted_op_list); process_rsc_state(rsc, node, on_fail, data_set); } if(delete_resource) { DeleteRsc(rsc, node, data_set); } if(saved_role > rsc->role) { rsc->role = saved_role; } } gboolean unpack_lrm_resources(node_t *node, crm_data_t * lrm_rsc_list, pe_working_set_t *data_set) { - CRM_DEV_ASSERT(node != NULL); - if(crm_assert_failed) { - return FALSE; - } + CRM_CHECK(node != NULL, return FALSE); crm_debug_3("Unpacking resources on %s", node->details->uname); xml_child_iter_filter( lrm_rsc_list, rsc_entry, XML_LRM_TAG_RESOURCE, unpack_lrm_rsc_state(node, rsc_entry, data_set); ); return TRUE; } #define sort_return(an_int) crm_free(a_uuid); crm_free(b_uuid); return an_int gint sort_op_by_callid(gconstpointer a, gconstpointer b) { char *a_uuid = NULL; char *b_uuid = NULL; 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); const char *a_key = cl_get_string(a, XML_ATTR_TRANSITION_MAGIC); const char *b_key = cl_get_string(b, XML_ATTR_TRANSITION_MAGIC); const char *a_xml_id = ID(a); const char *b_xml_id = ID(b); int a_id = -1; int b_id = -1; int a_rc = -1; int b_rc = -1; int a_status = -1; int b_status = -1; int a_call_id = -1; int b_call_id = -1; if(safe_str_eq(a_xml_id, b_xml_id)) { /* We have duplicate lrm_rsc_op entries in the status * section which is unliklely to be a good thing * - we can handle it easily enough, but we need to get * to the bottom of why its happening. */ pe_err("Duplicate lrm_rsc_op entries named %s", a_xml_id); sort_return(0); } - CRM_DEV_ASSERT(a_task_id != NULL && b_task_id != NULL); + CRM_CHECK(a_task_id != NULL && b_task_id != NULL, sort_return(0)); a_call_id = crm_parse_int(a_task_id, NULL); b_call_id = crm_parse_int(b_task_id, NULL); if(a_call_id == -1 && b_call_id == -1) { /* both are pending ops so it doesnt matter since * stops are never pending */ sort_return(0); } else if(a_call_id >= 0 && a_call_id < b_call_id) { crm_debug_2("%s (%d) < %s (%d) : call id", ID(a), a_call_id, ID(b), b_call_id); sort_return(-1); } else if(b_call_id >= 0 && a_call_id > b_call_id) { crm_debug_2("%s (%d) > %s (%d) : call id", ID(a), a_call_id, ID(b), b_call_id); sort_return(1); } crm_debug_3("%s (%d) == %s (%d) : continuing", ID(a), a_call_id, ID(b), b_call_id); /* now process pending ops */ - CRM_DEV_ASSERT(a_key != NULL && b_key != NULL); - CRM_DEV_ASSERT(decode_transition_magic( - a_key,&a_uuid,&a_id,&a_status, &a_rc)); - CRM_DEV_ASSERT(decode_transition_magic( - b_key,&b_uuid,&b_id,&b_status, &b_rc)); + CRM_CHECK(a_key != NULL && b_key != NULL, sort_return(0)); + CRM_CHECK(decode_transition_magic( + a_key,&a_uuid,&a_id,&a_status, &a_rc), sort_return(0)); + CRM_CHECK(decode_transition_magic( + b_key,&b_uuid,&b_id,&b_status, &b_rc), sort_return(0)); /* try and determin the relative age of the operation... * some pending operations (ie. a start) may have been supuerceeded * by a subsequent stop * * [a|b]_id == -1 means its a shutdown operation and _always_ comes last */ if(safe_str_neq(a_uuid, b_uuid) || a_id == b_id) { /* * some of the logic in here may be redundant... * * if the UUID from the TE doesnt match then one better * be a pending operation. * pending operations dont survive between elections and joins * because we query the LRM directly */ - CRM_DEV_ASSERT(a_call_id == -1 || b_call_id == -1); - CRM_DEV_ASSERT(a_call_id >= 0 || b_call_id >= 0); + CRM_CHECK(a_call_id == -1 || b_call_id == -1, sort_return(0)); + CRM_CHECK(a_call_id >= 0 || b_call_id >= 0, sort_return(0)); if(b_call_id == -1) { crm_debug_2("%s (%d) < %s (%d) : transition + call id", ID(a), a_call_id, ID(b), b_call_id); sort_return(-1); } if(a_call_id == -1) { crm_debug_2("%s (%d) > %s (%d) : transition + call id", ID(a), a_call_id, ID(b), b_call_id); sort_return(1); } } else if((a_id >= 0 && a_id < b_id) || b_id == -1) { crm_debug_2("%s (%d) < %s (%d) : transition", ID(a), a_id, ID(b), b_id); sort_return(-1); } else if((b_id >= 0 && a_id > b_id) || a_id == -1) { crm_debug_2("%s (%d) > %s (%d) : transition", ID(a), a_id, ID(b), b_id); sort_return(1); } /* we should never end up here */ crm_err("%s (%d:%d:%s) ?? %s (%d:%d:%s) : default", ID(a), a_call_id, a_id, a_uuid, ID(b), b_call_id, b_id, b_uuid); - CRM_DEV_ASSERT(FALSE); - sort_return(0); + CRM_CHECK(FALSE, sort_return(0)); } gboolean unpack_rsc_op(resource_t *rsc, node_t *node, crm_data_t *xml_op, int *max_call_id, enum action_fail_response *on_fail, pe_working_set_t *data_set) { const char *id = NULL; const char *task = NULL; const char *task_id = NULL; const char *actual_rc = NULL; const char *target_rc = NULL; const char *task_status = NULL; const char *interval_s = NULL; int interval = 0; int task_id_i = -1; int task_status_i = -2; int actual_rc_i = 0; action_t *action = NULL; gboolean is_stop_action = FALSE; crm_data_t *params = find_xml_node(xml_op, XML_TAG_PARAMS, FALSE); - 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; } + CRM_CHECK(rsc != NULL, return FALSE); + CRM_CHECK(node != NULL, return FALSE); + CRM_CHECK(xml_op != NULL, return FALSE); id = ID(xml_op); 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(id != 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; } + CRM_CHECK(id != NULL, return FALSE); + CRM_CHECK(task != NULL, return FALSE); + CRM_CHECK(task_status != NULL, return FALSE); task_status_i = crm_parse_int(task_status, NULL); - 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_CHECK(task_status_i <= LRM_OP_ERROR, return FALSE); + CRM_CHECK(task_status_i >= LRM_OP_PENDING, return FALSE); if(safe_str_eq(task, CRMD_ACTION_NOTIFY)) { /* safe to ignore these */ return TRUE; } crm_debug_2("Unpacking task %s/%s (call_id=%s, status=%s) on %s (role=%s)", rsc->id, task, task_id, task_status, node->details->uname, role2text(rsc->role)); if(params != NULL) { interval_s = crm_element_value(params, "interval"); if(interval_s != NULL) { interval = crm_parse_int(interval_s, NULL); } } if(params == NULL) { } else if(safe_str_eq(task, CRMD_ACTION_STATUS) && interval == 0) { /* ignore probes */ } else if(rsc->orphan == FALSE || data_set->stop_rsc_orphans == FALSE){ crm_data_t *op_match = NULL; crm_data_t *pdiff = NULL; GHashTable *local_rsc_params = NULL; crm_data_t *pnow = NULL; crm_debug_2("Checking parameters to %s action", task); xml_child_iter_filter( rsc->ops_xml, operation, "op", const char *name = crm_element_value(operation, "name"); int value = crm_get_msec( crm_element_value(operation, "interval")); if(interval <= 0) { break; } else if(safe_str_neq(name, task)) { continue; } else if(value != interval) { continue; } op_match = operation; ); if(interval > 0 && op_match == NULL) { if(data_set->stop_action_orphans == FALSE) { /* create a cancel action */ pe_config_warn("Ignoring orphan action: %s", id); return TRUE; } pe_config_warn("Orphan action will be stopped: %s", id); action = custom_action( rsc, crm_strdup(id), CRMD_ACTION_CANCEL, node, FALSE, TRUE, data_set); add_hash_param(action->extra, "interval", interval_s); add_hash_param(action->extra, "task", task); custom_action_order( rsc, NULL, action, rsc, stop_key(rsc), NULL, pe_ordering_optional, data_set); return TRUE; } action = custom_action(rsc, crm_strdup(id), task, node, TRUE, FALSE, data_set); local_rsc_params = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); unpack_instance_attributes( rsc->xml, XML_TAG_ATTR_SETS, node, local_rsc_params, NULL, 0, data_set); pnow = create_xml_node(NULL, XML_TAG_PARAMS); g_hash_table_foreach(action->extra, hash2field, pnow); g_hash_table_foreach(rsc->parameters, hash2field, pnow); g_hash_table_foreach(local_rsc_params, hash2field, pnow); xml_remove_prop(pnow, XML_ATTR_CRM_VERSION); xml_remove_prop(params, XML_ATTR_CRM_VERSION); xml_remove_prop(pnow, "is_managed"); xml_remove_prop(params, "is_managed"); /* ignore notify fields */ xml_remove_prop(params, "notify_stop_resource"); xml_remove_prop(params, "notify_stop_uname"); xml_remove_prop(params, "notify_start_resource"); xml_remove_prop(params, "notify_start_uname"); xml_remove_prop(params, "notify_active_resource"); xml_remove_prop(params, "notify_active_uname"); xml_remove_prop(params, "notify_inactive_resource"); xml_remove_prop(params, "notify_inactive_uname"); xml_remove_prop(params, "notify_promote_resource"); xml_remove_prop(params, "notify_promote_uname"); xml_remove_prop(params, "notify_demote_resource"); xml_remove_prop(params, "notify_demote_uname"); xml_remove_prop(params, "notify_master_resource"); xml_remove_prop(params, "notify_master_uname"); xml_remove_prop(params, "notify_slave_resource"); xml_remove_prop(params, "notify_slave_uname"); pdiff = diff_xml_object(params, pnow, TRUE); if(pdiff != NULL) { crm_info("Parameters to %s action changed", id); log_xml_diff(LOG_INFO, pdiff, __FUNCTION__); custom_action(rsc, crm_strdup(id), task, NULL, FALSE, TRUE, data_set); } g_hash_table_destroy(action->extra); crm_free(action->uuid); crm_free(action); free_xml(pnow); free_xml(pdiff); g_hash_table_destroy(local_rsc_params); action = NULL; } if(safe_str_eq(task, CRMD_ACTION_STOP)) { is_stop_action = TRUE; } if(task_status_i != LRM_OP_PENDING) { task_id_i = crm_parse_int(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) { - crm_err("%s: status=%d, task=%s", id, task_status_i, task_id); - return FALSE; - } + CRM_CHECK(task_id != NULL, return FALSE); + CRM_CHECK(task_id_i >= 0, return FALSE); if(task_id_i == *max_call_id) { crm_debug_2("Already processed this call"); return TRUE; } - CRM_DEV_ASSERT(task_id_i > *max_call_id); - if(crm_assert_failed) { return FALSE; } + CRM_CHECK(task_id_i > *max_call_id, return FALSE); } if(*max_call_id < task_id_i) { *max_call_id = task_id_i; } if(node->details->unclean) { crm_debug_2("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); } if(params != NULL) { target_rc = crm_element_value(params, XML_ATTR_TE_TARGET_RC); } actual_rc = crm_element_value(xml_op, XML_LRM_ATTR_RC); - CRM_DEV_ASSERT(actual_rc != NULL); - if(actual_rc != NULL) { - actual_rc_i = crm_parse_int(actual_rc, NULL); - } - + CRM_CHECK(actual_rc != NULL, return FALSE); + + actual_rc_i = crm_parse_int(actual_rc, NULL); if(target_rc != NULL && task_status_i != LRM_OP_PENDING) { crm_debug_2("Exit code from %s: %s vs. %s", task, target_rc, actual_rc); if(safe_str_eq(target_rc, actual_rc)) { task_status_i = LRM_OP_DONE; } else { task_status_i = LRM_OP_ERROR; } } if(EXECRA_NOT_RUNNING == actual_rc_i) { rsc->role = RSC_ROLE_STOPPED; if(safe_str_eq(task, CRMD_ACTION_STATUS)) { /* probe or stop action*/ crm_debug_2("%s: resource %s is stopped", id, rsc->id); return TRUE; } } else if(EXECRA_RUNNING_MASTER == actual_rc_i) { rsc->role = RSC_ROLE_MASTER; if(safe_str_eq(task, CRMD_ACTION_STATUS)) { crm_info("%s: resource %s is a master", id, rsc->id); return TRUE; } } else if(EXECRA_FAILED_MASTER == actual_rc_i) { rsc->role = RSC_ROLE_MASTER; task_status_i = LRM_OP_ERROR; } if(task_status_i == LRM_OP_ERROR || task_status_i == LRM_OP_TIMEOUT || task_status_i == LRM_OP_NOTSUPPORTED) { action = custom_action(rsc, crm_strdup(id), task, NULL, TRUE, TRUE, data_set); if(action->on_fail == action_fail_ignore) { task_status_i = LRM_OP_DONE; } } 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_ACTION_START)) { rsc->start_pending = TRUE; rsc->role = RSC_ROLE_STARTED; /* make sure it is re-issued but, * only if we have quorum */ if(data_set->have_quorum == TRUE || data_set->no_quorum_policy == no_quorum_ignore){ /* do not specify the node, we may want * to start it elsewhere */ start_action(rsc, NULL, FALSE); } } else if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) { rsc->role = RSC_ROLE_MASTER; } else if(rsc->role > RSC_ROLE_STOPPED) { crm_debug_2("Re-issuing pending recurring task:" " %s for %s on %s", task, rsc->id, node->details->id); /* do not specify the node, we may want * to start it elsewhere */ custom_action(rsc, crm_strdup(id), task, NULL, FALSE, TRUE, data_set); } break; case LRM_OP_DONE: crm_debug_3("%s/%s completed on %s", rsc->id, task, node->details->uname); if(is_stop_action) { rsc->role = RSC_ROLE_STOPPED; *on_fail = action_fail_ignore; rsc->next_role = RSC_ROLE_UNKNOWN; } else if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) { rsc->role = RSC_ROLE_MASTER; } else if(safe_str_eq(task, CRMD_ACTION_DEMOTE)) { rsc->role = RSC_ROLE_SLAVE; } else { /* make sure its already created and is optional * * creating it now tells Recurring() * that it can safely leave it optional */ if(rsc->role < RSC_ROLE_STARTED) { crm_debug_2("%s active on %s", rsc->id, node->details->uname); rsc->role = RSC_ROLE_STARTED; } /* the != start check is so i dont have to * update all the old testcases */ if(interval > 0 || safe_str_neq(task, CRMD_ACTION_START)) { crm_debug_2("%s: %s active on %s", rsc->id, id, node->details->uname); custom_action(rsc, crm_strdup(id), task, node, TRUE, TRUE, data_set); } } break; case LRM_OP_ERROR: case LRM_OP_TIMEOUT: case LRM_OP_NOTSUPPORTED: crm_warn("Processing failed op (%s) for %s on %s", id, rsc->id, node->details->uname); action = custom_action( rsc, crm_strdup(id), task, NULL, TRUE, TRUE, data_set); if(*on_fail < action->on_fail) { *on_fail = action->on_fail; } /* if(action->on_fail == action_fail_ignore) { */ /* } else */ if(task_status_i == LRM_OP_NOTSUPPORTED || is_stop_action || safe_str_eq(task, CRMD_ACTION_START) ) { crm_warn("Handling failed %s for %s on %s", task, rsc->id, node->details->uname); rsc2node_new("dont_run__failed_stopstart", rsc, -INFINITY, node, data_set); } if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) { rsc->role = RSC_ROLE_MASTER; } else if(safe_str_eq(task, CRMD_ACTION_DEMOTE)) { rsc->role = RSC_ROLE_MASTER; } else if(rsc->role < RSC_ROLE_STARTED) { rsc->role = RSC_ROLE_STARTED; } crm_debug_2("Resource %s: role=%s, unclean=%s, on_fail=%s, fail_role=%s", rsc->id, role2text(rsc->role), node->details->unclean?"true":"false", fail2text(action->on_fail), role2text(action->fail_role)); if(action->fail_role != RSC_ROLE_STARTED && rsc->next_role < action->fail_role) { rsc->next_role = action->fail_role; } if(action->fail_role == RSC_ROLE_STOPPED) { /* make sure it doesnt come up again */ native_assign_color(rsc, data_set->no_color); } break; case LRM_OP_CANCELLED: /* do nothing?? */ pe_err("Dont know what to do for cancelled ops yet"); break; } crm_debug_2("Resource %s after %s: role=%s", rsc->id, task, role2text(rsc->role)); return TRUE; } gboolean rsc_colocation_new(const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh, const char *state_lh, const char *state_rh) { rsc_colocation_t *new_con = NULL; rsc_colocation_t *inverted_con = NULL; if(rsc_lh == NULL){ pe_config_err("No resource found for LHS %s", id); return FALSE; } else if(rsc_rh == NULL){ pe_config_err("No resource found for RHS of %s", id); return FALSE; } crm_malloc0(new_con, sizeof(rsc_colocation_t)); if(new_con == NULL) { return FALSE; } if(safe_str_eq(state_lh, CRMD_ACTION_STARTED)) { state_lh = NULL; } if(safe_str_eq(state_rh, CRMD_ACTION_STARTED)) { state_rh = NULL; } new_con->id = id; new_con->rsc_lh = rsc_lh; new_con->rsc_rh = rsc_rh; new_con->strength = strength; new_con->state_lh = state_lh; new_con->state_rh = state_rh; inverted_con = invert_constraint(new_con); crm_debug_4("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_debug_4("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; } /* LHS before RHS */ gboolean custom_action_order( resource_t *lh_rsc, char *lh_action_task, action_t *lh_action, resource_t *rh_rsc, char *rh_action_task, action_t *rh_action, enum pe_ordering type, pe_working_set_t *data_set) { order_constraint_t *order = NULL; if((lh_action == NULL && lh_rsc == NULL) || (rh_action == NULL && rh_rsc == NULL)){ pe_config_err("Invalid inputs lh_rsc=%p, lh_a=%p," " rh_rsc=%p, rh_a=%p", lh_rsc, lh_action, rh_rsc, rh_action); crm_free(lh_action_task); crm_free(rh_action_task); return FALSE; } crm_malloc0(order, sizeof(order_constraint_t)); if(order == NULL) { return FALSE; } order->id = data_set->order_id++; order->type = type; 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; data_set->ordering_constraints = g_list_append( data_set->ordering_constraints, order); if(lh_rsc != NULL && rh_rsc != NULL) { crm_debug_4("Created ordering constraint %d (%s):" " %s/%s before %s/%s", order->id, ordering_type2text(order->type), lh_rsc->id, lh_action_task, rh_rsc->id, rh_action_task); } else if(lh_rsc != NULL) { crm_debug_4("Created ordering constraint %d (%s):" " %s/%s before action %d (%s)", order->id, ordering_type2text(order->type), lh_rsc->id, lh_action_task, rh_action->id, rh_action_task); } else if(rh_rsc != NULL) { crm_debug_4("Created ordering constraint %d (%s):" " action %d (%s) before %s/%s", order->id, ordering_type2text(order->type), lh_action->id, lh_action_task, rh_rsc->id, rh_action_task); } else { crm_debug_4("Created ordering constraint %d (%s):" " action %d (%s) before action %d (%s)", order->id, ordering_type2text(order->type), lh_action->id, lh_action_task, rh_action->id, rh_action_task); } return TRUE; } gboolean unpack_rsc_colocation(crm_data_t * xml_obj, pe_working_set_t *data_set) { 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); const char *state_lh = crm_element_value(xml_obj, XML_RULE_ATTR_FROMSTATE); const char *state_rh = crm_element_value(xml_obj, XML_RULE_ATTR_TOSTATE); resource_t *rsc_lh = pe_find_resource(data_set->resources, id_lh); resource_t *rsc_rh = pe_find_resource(data_set->resources, id_rh); if(rsc_lh == NULL) { pe_config_err("No resource (con=%s, rsc=%s)", id, id_lh); return FALSE; } else if(rsc_rh == NULL) { pe_config_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, state_lh, state_rh); } static const char * invert_action(const char *action) { if(safe_str_eq(action, CRMD_ACTION_START)) { return CRMD_ACTION_STOP; } else if(safe_str_eq(action, CRMD_ACTION_STOP)) { return CRMD_ACTION_START; } else if(safe_str_eq(action, CRMD_ACTION_PROMOTE)) { return CRMD_ACTION_DEMOTE; } else if(safe_str_eq(action, CRMD_ACTION_DEMOTE)) { return CRMD_ACTION_PROMOTE; } else if(safe_str_eq(action, CRMD_ACTION_STARTED)) { return CRMD_ACTION_STOPPED; } else if(safe_str_eq(action, CRMD_ACTION_STOPPED)) { return CRMD_ACTION_STARTED; } pe_err("Unknown action: %s", action); return NULL; } gboolean unpack_rsc_order(crm_data_t * xml_obj, pe_working_set_t *data_set) { 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 *action_rh = crm_element_value(xml_obj, XML_CONS_ATTR_TOACTION); const char *symmetrical = crm_element_value( xml_obj, XML_CONS_ATTR_SYMMETRICAL); resource_t *rsc_lh = NULL; resource_t *rsc_rh = NULL; if(xml_obj == NULL) { pe_config_err("No constraint object to process."); return FALSE; } else if(id == NULL) { pe_config_err("%s constraint must have an id", crm_element_name(xml_obj)); return FALSE; } else if(id_lh == NULL || id_rh == NULL) { pe_config_err("Constraint %s needs two sides lh: %s rh: %s", id, crm_str(id_lh), crm_str(id_rh)); return FALSE; } if(action == NULL) { action = CRMD_ACTION_START; } if(action_rh == NULL) { action_rh = action; } - CRM_DEV_ASSERT(action != NULL); - CRM_DEV_ASSERT(action_rh != NULL); + CRM_CHECK(action != NULL, return FALSE); + CRM_CHECK(action_rh != NULL, return FALSE); if(safe_str_eq(type, "before")) { id_lh = crm_element_value(xml_obj, XML_CONS_ATTR_TO); id_rh = crm_element_value(xml_obj, XML_CONS_ATTR_FROM); action = crm_element_value(xml_obj, XML_CONS_ATTR_TOACTION); action_rh = crm_element_value(xml_obj, XML_CONS_ATTR_ACTION); if(action_rh == NULL) { action_rh = CRMD_ACTION_START; } if(action == NULL) { action = action_rh; } } - CRM_DEV_ASSERT(action != NULL); - CRM_DEV_ASSERT(action_rh != NULL); + CRM_CHECK(action != NULL, return FALSE); + CRM_CHECK(action_rh != NULL, return FALSE); rsc_lh = pe_find_resource(data_set->resources, id_rh); rsc_rh = pe_find_resource(data_set->resources, id_lh); if(rsc_lh == NULL) { pe_config_err("Constraint %s: no resource found for LHS of %s", id, id_lh); return FALSE; } else if(rsc_rh == NULL) { pe_config_err("Constraint %s: no resource found for RHS of %s", id, id_rh); return FALSE; } custom_action_order( rsc_lh, generate_op_key(rsc_lh->id, action, 0), NULL, rsc_rh, generate_op_key(rsc_rh->id, action_rh, 0), NULL, pe_ordering_optional, data_set); if(rsc_rh->restart_type == pe_restart_restart && safe_str_eq(action, action_rh)) { if(safe_str_eq(action, CRMD_ACTION_START)) { crm_debug_2("Recover start-start: %s-%s", rsc_lh->id, rsc_rh->id); order_start_start(rsc_lh, rsc_rh, pe_ordering_recover); } else if(safe_str_eq(action, CRMD_ACTION_STOP)) { crm_debug_2("Recover stop-stop: %s-%s", rsc_rh->id, rsc_lh->id); order_stop_stop(rsc_rh, rsc_lh, pe_ordering_recover); } } cl_str_to_boolean(symmetrical, &symmetrical_bool); if(symmetrical_bool == FALSE) { return TRUE; } action = invert_action(action); action_rh = invert_action(action_rh); custom_action_order( rsc_rh, generate_op_key(rsc_rh->id, action_rh, 0), NULL, rsc_lh, generate_op_key(rsc_lh->id, action, 0), NULL, pe_ordering_optional, data_set); if(rsc_lh->restart_type == pe_restart_restart && safe_str_eq(action, action_rh)) { if(safe_str_eq(action, CRMD_ACTION_START)) { crm_debug_2("Recover start-start (2): %s-%s", rsc_lh->id, rsc_rh->id); order_start_start(rsc_lh, rsc_rh, pe_ordering_recover); } else if(safe_str_eq(action, CRMD_ACTION_STOP)) { crm_debug_2("Recover stop-stop (2): %s-%s", rsc_rh->id, rsc_lh->id); order_stop_stop(rsc_rh, rsc_lh, pe_ordering_recover); } } return TRUE; } gboolean add_node_attrs(crm_data_t *xml_obj, node_t *node, pe_working_set_t *data_set) { 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, data_set->dc_uuid)) { data_set->dc_node = node; 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, XML_TAG_ATTR_SETS, node, node->details->attrs, NULL, 0, data_set); return TRUE; } gboolean unpack_rsc_location(crm_data_t * xml_obj, pe_working_set_t *data_set) { 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(data_set->resources, id_lh); if(rsc_lh == NULL) { /* only a warn as BSC adds the constraint then the resource */ pe_config_warn("No resource (con=%s, rsc=%s)", id, id_lh); return FALSE; } else if(rsc_lh->is_managed == FALSE) { crm_debug_2("Ignoring constraint %s: resource %s not managed", id, id_lh); return FALSE; } xml_child_iter_filter( xml_obj, rule_xml, XML_TAG_RULE, crm_debug_2("Unpacking %s/%s", id, ID(rule_xml)); generate_location_rule(rsc_lh, rule_xml, data_set); ); return TRUE; } rsc_to_node_t * generate_location_rule( resource_t *rsc, crm_data_t *rule_xml, pe_working_set_t *data_set) { const char *rule_id = NULL; const char *score = NULL; const char *boolean = NULL; const char *role = NULL; const char *attr_score = NULL; GListPtr match_L = NULL; int score_f = 0; gboolean do_and = TRUE; gboolean accept = TRUE; gboolean raw_score = TRUE; rsc_to_node_t *location_rule = NULL; rule_id = crm_element_value(rule_xml, XML_ATTR_ID); boolean = crm_element_value(rule_xml, XML_RULE_ATTR_BOOLEAN_OP); role = crm_element_value(rule_xml, XML_RULE_ATTR_ROLE); crm_debug_2("processing rule: %s", rule_id); if(role != NULL && text2role(role) == RSC_ROLE_UNKNOWN) { pe_err("Bad role specified for %s: %s", rule_id, role); return NULL; } score = crm_element_value(rule_xml, XML_RULE_ATTR_SCORE); if(score != NULL) { score_f = char2score(score); } else { score = crm_element_value( rule_xml, XML_RULE_ATTR_SCORE_ATTRIBUTE); if(score == NULL) { score = crm_element_value( rule_xml, XML_RULE_ATTR_SCORE_MANGLED); } if(score != NULL) { raw_score = FALSE; } } if(safe_str_eq(boolean, "or")) { do_and = FALSE; } location_rule = rsc2node_new(rule_id, rsc, 0, NULL, data_set); if(location_rule == NULL) { return NULL; } if(role != NULL) { crm_debug_2("Setting role filter: %s", role); location_rule->role_filter = text2role(role); } if(do_and) { match_L = node_list_dup(data_set->nodes, FALSE); slist_iter( node, node_t, match_L, lpc, node->weight = score_f; ); } xml_child_iter( rule_xml, expr, enum expression_type type = find_expression_type(expr); if(type == not_expr) { pe_err("Expression <%s id=%s...> is not valid", crm_element_name(expr), crm_str(ID(expr))); continue; } slist_iter( node, node_t, data_set->nodes, lpc, if(type == nested_rule) { accept = test_rule(expr, node, rsc, data_set); } else { accept = test_expression( expr, node, rsc, data_set); } if(raw_score == FALSE) { attr_score = g_hash_table_lookup( node->details->attrs, score); if(attr_score == NULL) { accept = FALSE; pe_warn("node %s did not have a value" " for %s", node->details->uname, score); } else { score_f = char2score(score); } } if(!do_and && accept) { node_t *local = pe_find_node_id( match_L, node->details->id); if(local == NULL) { local = node_copy(node); match_L = g_list_append(match_L, local); } local->weight = merge_weights( local->weight, score_f); crm_debug_5("node %s already matched", node->details->uname); } else if(do_and && !accept) { /* remove it */ node_t *delete = pe_find_node_id( match_L, node->details->id); if(delete != NULL) { match_L = g_list_remove(match_L,delete); crm_debug_5("node %s did not match", node->details->uname); } crm_free(delete); } ); ); location_rule->node_list_rh = match_L; if(location_rule->node_list_rh == NULL) { crm_debug_2("No matching nodes for rule %s", rule_id); return NULL; } crm_debug_2("%s: %d nodes matched", rule_id, g_list_length(location_rule->node_list_rh)); crm_action_debug_3(print_rsc_to_node("Added", location_rule, FALSE)); return location_rule; } diff --git a/crm/pengine/utils.c b/crm/pengine/utils.c index 44ba5d8aa6..a4514b674b 100644 --- a/crm/pengine/utils.c +++ b/crm/pengine/utils.c @@ -1,1850 +1,1838 @@ -/* $Id: utils.c,v 1.125 2006/02/16 16:01:33 andrew Exp $ */ +/* $Id: utils.c,v 1.126 2006/03/18 17:23:48 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 void print_str_str(gpointer key, gpointer value, gpointer user_data); gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data); void unpack_operation( action_t *action, crm_data_t *xml_obj, pe_working_set_t* data_set); /* only for rsc_colocation constraints */ rsc_colocation_t * invert_constraint(rsc_colocation_t *constraint) { rsc_colocation_t *inverted_con = NULL; crm_debug_3("Inverting constraint"); if(constraint == NULL) { pe_err("Cannot invert NULL constraint"); return NULL; } crm_malloc0(inverted_con, sizeof(rsc_colocation_t)); if(inverted_con == NULL) { return NULL; } inverted_con->id = constraint->id; inverted_con->strength = constraint->strength; /* swap the direction */ inverted_con->rsc_lh = constraint->rsc_rh; inverted_con->rsc_rh = constraint->rsc_lh; inverted_con->state_lh = constraint->state_rh; inverted_con->state_rh = constraint->state_lh; crm_action_debug_3( print_rsc_colocation("Inverted constraint", inverted_con, FALSE)); return inverted_con; } /* are the contents of list1 and list2 equal * nodes with weight < 0 are ignored if filter == TRUE * * slow but linear * */ gboolean node_list_eq(GListPtr list1, GListPtr list2, gboolean filter) { node_t *other_node; GListPtr lhs = list1; GListPtr rhs = list2; slist_iter( node, node_t, lhs, lpc, if(node == NULL || (filter && node->weight < 0)) { continue; } other_node = (node_t*) pe_find_node_id(rhs, node->details->id); if(other_node == NULL || other_node->weight < 0) { return FALSE; } ); lhs = list2; rhs = list1; slist_iter( node, node_t, lhs, lpc, if(node == NULL || (filter && node->weight < 0)) { continue; } other_node = (node_t*) pe_find_node_id(rhs, node->details->id); if(other_node == NULL || other_node->weight < 0) { return FALSE; } ); return TRUE; } /* the intersection of list1 and list2 */ GListPtr node_list_and(GListPtr list1, GListPtr list2, gboolean filter) { GListPtr result = NULL; unsigned lpc = 0; for(lpc = 0; lpc < g_list_length(list1); lpc++) { node_t *node = (node_t*)g_list_nth_data(list1, lpc); node_t *other_node = pe_find_node_id(list2, node->details->id); node_t *new_node = NULL; if(other_node != NULL) { new_node = node_copy(node); crm_debug_3("Copied node %s: %d", new_node->details->uname, new_node->weight); } if(new_node != NULL) { new_node->weight = merge_weights( new_node->weight, other_node->weight); crm_debug_3("New node weight for %s: %d", new_node->details->uname, new_node->weight); if(filter && new_node->weight < 0) { crm_free(new_node); new_node = NULL; } } if(new_node != NULL) { result = g_list_append(result, new_node); } } return result; } /* list1 - list2 */ GListPtr node_list_minus(GListPtr list1, GListPtr list2, gboolean filter) { GListPtr result = NULL; slist_iter( node, node_t, list1, lpc, node_t *other_node = pe_find_node_id(list2, node->details->id); node_t *new_node = NULL; if(node == NULL || other_node != NULL || (filter && node->weight < 0)) { continue; } new_node = node_copy(node); result = g_list_append(result, new_node); ); crm_debug_3("Minus result len: %d", g_list_length(result)); return result; } /* list1 + list2 - (intersection of list1 and list2) */ GListPtr node_list_xor(GListPtr list1, GListPtr list2, gboolean filter) { GListPtr result = NULL; slist_iter( node, node_t, list1, lpc, node_t *new_node = NULL; node_t *other_node = (node_t*) pe_find_node_id(list2, node->details->id); if(node == NULL || other_node != NULL || (filter && node->weight < 0)) { continue; } new_node = node_copy(node); result = g_list_append(result, new_node); ); slist_iter( node, node_t, list2, lpc, node_t *new_node = NULL; node_t *other_node = (node_t*) pe_find_node_id(list1, node->details->id); if(node == NULL || other_node != NULL || (filter && node->weight < 0)) { continue; } new_node = node_copy(node); result = g_list_append(result, new_node); ); crm_debug_3("Xor result len: %d", g_list_length(result)); return result; } GListPtr node_list_or(GListPtr list1, GListPtr list2, gboolean filter) { node_t *other_node = NULL; GListPtr result = NULL; gboolean needs_filter = FALSE; result = node_list_dup(list1, filter); slist_iter( node, node_t, list2, lpc, if(node == NULL) { continue; } other_node = (node_t*)pe_find_node_id( result, node->details->id); if(other_node != NULL) { other_node->weight = merge_weights( other_node->weight, node->weight); if(filter && node->weight < 0) { needs_filter = TRUE; } } else if(filter == FALSE || node->weight >= 0) { node_t *new_node = node_copy(node); result = g_list_append(result, new_node); } ); /* not the neatest way, but the most expedient for now */ if(filter && needs_filter) { GListPtr old_result = result; result = node_list_dup(old_result, filter); pe_free_shallow_adv(old_result, TRUE); } return result; } GListPtr node_list_dup(GListPtr list1, gboolean filter) { GListPtr result = NULL; slist_iter( this_node, node_t, list1, lpc, node_t *new_node = NULL; if(filter && this_node->weight < 0) { continue; } new_node = node_copy(this_node); if(new_node != NULL) { result = g_list_append(result, new_node); } ); return result; } node_t * node_copy(node_t *this_node) { node_t *new_node = NULL; - CRM_DEV_ASSERT(this_node != NULL); - if(this_node == NULL) { - pe_err("Failed copy of node."); - return NULL; - } + CRM_CHECK(this_node != NULL, return NULL); crm_malloc0(new_node, sizeof(node_t)); - CRM_DEV_ASSERT(new_node != NULL); - if(new_node == NULL) { - return NULL; - } + CRM_CHECK(new_node != NULL, return NULL); crm_debug_5("Copying %p (%s) to %p", this_node, this_node->details->uname, new_node); new_node->weight = this_node->weight; new_node->fixed = this_node->fixed; new_node->details = this_node->details; return new_node; } /* * Create a new color with the contents of "nodes" as the list of * possible nodes that resources with this color can be run on. * * Typically, when creating a color you will provide the node list from * the resource you will first assign the color to. * * If "colors" != NULL, it will be added to that list * If "resources" != NULL, it will be added to every provisional resource * in that list */ color_t * create_color( pe_working_set_t *data_set, resource_t *resource, GListPtr node_list) { color_t *new_color = NULL; crm_debug_5("Creating color"); crm_malloc0(new_color, sizeof(color_t)); if(new_color == NULL) { return NULL; } new_color->id = data_set->color_id++; new_color->local_weight = 1.0; crm_debug_5("Creating color details"); crm_malloc0(new_color->details, sizeof(struct color_shared_s)); if(new_color->details == NULL) { crm_free(new_color); return NULL; } new_color->details->id = new_color->id; new_color->details->highest_priority = -1; new_color->details->chosen_node = NULL; new_color->details->candidate_nodes = NULL; new_color->details->allocated_resources = NULL; new_color->details->pending = TRUE; if(resource != NULL) { crm_debug_5("populating node list"); new_color->details->highest_priority = resource->priority; new_color->details->candidate_nodes = node_list_dup(node_list, TRUE); } crm_action_debug_3(print_color("Created color", new_color, TRUE)); - CRM_DEV_ASSERT(data_set != NULL); - if(crm_assert_failed == FALSE) { - data_set->colors = g_list_append(data_set->colors, new_color); - } + CRM_CHECK(data_set != NULL, return NULL); + data_set->colors = g_list_append(data_set->colors, new_color); return new_color; } color_t * copy_color(color_t *a_color) { color_t *color_copy = NULL; if(a_color == NULL) { pe_err("Cannot copy NULL"); return NULL; } crm_malloc0(color_copy, sizeof(color_t)); if(color_copy != NULL) { color_copy->id = a_color->id; color_copy->details = a_color->details; color_copy->local_weight = 1.0; } return color_copy; } resource_t * pe_find_resource(GListPtr rsc_list, const char *id) { unsigned lpc = 0; resource_t *rsc = NULL; resource_t *child_rsc = NULL; crm_debug_4("Looking for %s in %d objects", id, g_list_length(rsc_list)); for(lpc = 0; lpc < g_list_length(rsc_list); lpc++) { rsc = g_list_nth_data(rsc_list, lpc); if(rsc != NULL && safe_str_eq(rsc->id, id)){ crm_debug_4("Found a match for %s", id); return rsc; } } for(lpc = 0; lpc < g_list_length(rsc_list); lpc++) { rsc = g_list_nth_data(rsc_list, lpc); child_rsc = rsc->fns->find_child(rsc, id); if(child_rsc != NULL) { crm_debug_4("Found a match for %s in %s", id, rsc->id); return child_rsc; } } /* error */ return NULL; } node_t * pe_find_node_id(GListPtr nodes, const char *id) { unsigned lpc = 0; node_t *node = NULL; for(lpc = 0; lpc < g_list_length(nodes); lpc++) { node = g_list_nth_data(nodes, lpc); if(safe_str_eq(node->details->id, id)) { return node; } } /* error */ return NULL; } gint gslist_color_compare(gconstpointer a, gconstpointer b); color_t * find_color(GListPtr candidate_colors, color_t *other_color) { GListPtr tmp = g_list_find_custom(candidate_colors, other_color, gslist_color_compare); if(tmp != NULL) { return (color_t *)tmp->data; } return NULL; } gint gslist_color_compare(gconstpointer a, gconstpointer b) { const color_t *color_a = (const color_t*)a; const color_t *color_b = (const color_t*)b; /* crm_debug_5("%d vs. %d", a?color_a->id:-2, b?color_b->id:-2); */ if(a == b) { return 0; } else if(a == NULL || b == NULL) { return 1; } else if(color_a->id == color_b->id) { return 0; } return 1; } gint sort_rsc_priority(gconstpointer a, gconstpointer b) { const resource_t *resource1 = (const resource_t*)a; const resource_t *resource2 = (const resource_t*)b; if(a == NULL && b == NULL) { return 0; } if(a == NULL) { return 1; } if(b == NULL) { return -1; } if(resource1->priority > resource2->priority) { return -1; } if(resource1->priority < resource2->priority) { return 1; } return 0; } gint sort_rsc_node_weight(gconstpointer a, gconstpointer b) { const resource_t *resource1 = (const resource_t*)a; const resource_t *resource2 = (const resource_t*)b; const color_t *color1 = NULL; const color_t *color2 = NULL; const node_t *node1 = NULL; const node_t *node2 = NULL; CRM_ASSERT(resource1 != NULL); CRM_ASSERT(resource2 != NULL); color1 = resource1->color; color2 = resource2->color; - CRM_DEV_ASSERT(color1 != NULL); - CRM_DEV_ASSERT(color2 != NULL); + CRM_CHECK(color1 != NULL, return 0); + CRM_CHECK(color2 != NULL, return 0); node1 = color1->details->chosen_node; node2 = color2->details->chosen_node; if(node1 == NULL && node2 == NULL) { return 0; } if(node1 == NULL) { return 1; } if(node2 == NULL) { return -1; } CRM_ASSERT(node1 != NULL); CRM_ASSERT(node2 != NULL); if(node1->weight > node2->weight) { crm_debug("%s (%d) > %s (%d) : %s vs. %s", node1->details->id, node1->weight, node2->details->id, node2->weight, resource1->id, resource2->id); return -1; } if(node1->weight < node2->weight) { crm_debug("%s (%d) < %s (%d) : %s vs. %s", node1->details->id, node1->weight, node2->details->id, node2->weight, resource1->id, resource2->id); return 1; } crm_debug("%s (%d) == %s (%d) : %s vs. %s", node1->details->id, node1->weight, node2->details->id, node2->weight, resource1->id, resource2->id); return 0; } /* lowest to highest */ gint sort_action_id(gconstpointer a, gconstpointer b) { const action_wrapper_t *action_wrapper2 = (const action_wrapper_t*)a; const action_wrapper_t *action_wrapper1 = (const action_wrapper_t*)b; if(a == NULL) { return 1; } if(b == NULL) { return -1; } if(action_wrapper1->action->id > action_wrapper2->action->id) { return -1; } if(action_wrapper1->action->id < action_wrapper2->action->id) { return 1; } return 0; } gint sort_cons_strength(gconstpointer a, gconstpointer b) { const rsc_colocation_t *rsc_constraint1 = (const rsc_colocation_t*)a; const rsc_colocation_t *rsc_constraint2 = (const rsc_colocation_t*)b; if(a == NULL) { return 1; } if(b == NULL) { return -1; } if(rsc_constraint1->strength > rsc_constraint2->strength) { return 1; } if(rsc_constraint1->strength < rsc_constraint2->strength) { return -1; } return 0; } gint sort_color_weight(gconstpointer a, gconstpointer b) { const color_t *color1 = (const color_t*)a; const color_t *color2 = (const color_t*)b; if(a == NULL) { return 1; } if(b == NULL) { return -1; } if(color1->local_weight > color2->local_weight) { return -1; } if(color1->local_weight < color2->local_weight) { return 1; } return 0; } /* return -1 if 'a' is more preferred * return 1 if 'b' is more preferred */ gint sort_node_weight(gconstpointer a, gconstpointer b) { const node_t *node1 = (const node_t*)a; const node_t *node2 = (const node_t*)b; int node1_weight = 0; int node2_weight = 0; if(a == NULL) { return 1; } if(b == NULL) { return -1; } node1_weight = node1->weight; node2_weight = node2->weight; if(node1->details->unclean || node1->details->shutdown) { node1_weight = -INFINITY; } if(node2->details->unclean || node2->details->shutdown) { node2_weight = -INFINITY; } if(node1_weight > node2_weight) { crm_debug_2("%s (%d) > %s (%d) : weight", node1->details->uname, node1_weight, node2->details->uname, node2_weight); return -1; } if(node1_weight < node2_weight) { crm_debug_2("%s (%d) < %s (%d) : weight", node1->details->uname, node1_weight, node2->details->uname, node2_weight); return 1; } crm_debug_3("%s (%d) == %s (%d) : weight", node1->details->uname, node1_weight, node2->details->uname, node2_weight); /* now try to balance resources across the cluster */ if(node1->details->num_resources < node2->details->num_resources) { crm_debug_2("%s (%d) < %s (%d) : resources", node1->details->uname, node1->details->num_resources, node2->details->uname, node2->details->num_resources); return -1; } else if(node1->details->num_resources > node2->details->num_resources) { crm_debug_2("%s (%d) > %s (%d) : resources", node1->details->uname, node1->details->num_resources, node2->details->uname, node2->details->num_resources); return 1; } crm_debug_4("%s = %s", node1->details->uname, node2->details->uname); return 0; } action_t * custom_action(resource_t *rsc, char *key, const char *task, node_t *on_node, gboolean optional, gboolean save_action, pe_working_set_t *data_set) { action_t *action = NULL; GListPtr possible_matches = NULL; - CRM_DEV_ASSERT(key != NULL); - if(crm_assert_failed) { return NULL; } - - CRM_DEV_ASSERT(task != NULL); - if(crm_assert_failed) { return NULL; } + CRM_CHECK(key != NULL, return NULL); + CRM_CHECK(task != NULL, return NULL); if(save_action && rsc != NULL) { possible_matches = find_actions(rsc->actions, key, on_node); } if(possible_matches != NULL) { crm_free(key); if(g_list_length(possible_matches) > 1) { pe_warn("Action %s for %s on %s exists %d times", task, rsc?rsc->id:"", on_node?on_node->details->uname:"", g_list_length(possible_matches)); } action = g_list_nth_data(possible_matches, 0); crm_debug_4("Found existing action (%d) %s for %s on %s", action->id, task, rsc?rsc->id:"", on_node?on_node->details->uname:""); } if(action == NULL) { crm_debug_2("Creating action %d: %s for %s on %s", data_set->action_id, task, rsc?rsc->id:"", on_node?on_node->details->uname:""); crm_malloc0(action, sizeof(action_t)); if(action != NULL) { if(save_action) { action->id = data_set->action_id++; } else { action->id = 0; } action->rsc = rsc; action->task = task; action->node = on_node; action->actions_before = NULL; action->actions_after = NULL; action->failure_is_fatal = TRUE; action->pseudo = FALSE; action->dumped = FALSE; action->runnable = TRUE; action->processed = FALSE; action->optional = TRUE; action->seen_count = 0; action->extra = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); /* include our version number... * so future versions know what to be compatible * with when we're DC */ add_hash_param(action->extra, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET); if(save_action) { data_set->actions = g_list_append( data_set->actions, action); } action->uuid = key; if(rsc != NULL) { action->op_entry = find_rsc_op_entry(rsc, key); unpack_operation( action, action->op_entry, data_set); if(save_action) { rsc->actions = g_list_append( rsc->actions, action); } } crm_debug_4("Action %d created", action->id); } } if(optional == FALSE && action->optional) { crm_debug_2("Action %d (%s) marked manditory", action->id, action->uuid); action->optional = FALSE; } if(rsc != NULL) { enum action_tasks a_task = text2task(action->task); if(action->node != NULL) { unpack_instance_attributes( action->op_entry, XML_TAG_ATTR_SETS, action->node, action->extra, NULL,0, data_set); } if(action->node == NULL) { action->runnable = FALSE; } else if(rsc->is_managed == FALSE) { crm_warn("Action %s %s is for %s (unmanaged)", action->uuid, task, rsc->id); action->optional = TRUE; /* action->runnable = FALSE; */ #if 0 } else if(action->node->details->unclean) { crm_warn("Action %s on %s is unrunnable (unclean)", action->uuid, action->node?action->node->details->uname:""); action->runnable = FALSE; #endif } else if(action->node->details->online == FALSE) { action->runnable = FALSE; crm_warn("Action %s on %s is unrunnable (offline)", action->uuid, action->node->details->uname); if(action->rsc->is_managed && save_action && a_task == stop_rsc) { crm_warn("Marking node %s unclean", action->node->details->uname); action->node->details->unclean = TRUE; } } else if(action->needs == rsc_req_nothing) { crm_debug_2("Action %s doesnt require anything", action->uuid); action->runnable = TRUE; #if 0 /* * No point checking this * - if we dont have quorum we cant stonith anyway */ } else if(action->needs == rsc_req_stonith) { crm_debug_2("Action %s requires only stonith", action->uuid); action->runnable = TRUE; #endif } else if(data_set->have_quorum == FALSE && data_set->no_quorum_policy == no_quorum_stop) { action->runnable = FALSE; crm_debug("%s\t%s %s (cancelled : quorum)", action->node->details->uname, action->task, rsc->id); } else if(data_set->have_quorum == FALSE && data_set->no_quorum_policy == no_quorum_freeze) { crm_debug_2("Check resource is already active"); if(rsc->fns->active(rsc, TRUE) == FALSE) { action->runnable = FALSE; crm_debug("%s\t%s %s (cancelled : quorum freeze)", action->node->details->uname, action->task, rsc->id); } } else { crm_debug_2("Action %s is runnable", action->uuid); action->runnable = TRUE; } if(save_action) { switch(a_task) { case stop_rsc: rsc->stopping = TRUE; break; case start_rsc: rsc->starting = FALSE; if(action->runnable) { rsc->starting = TRUE; } break; default: break; } } } return action; } void unpack_operation( action_t *action, crm_data_t *xml_obj, pe_working_set_t* data_set) { int lpc = 0; const char *value = NULL; const char *fields[] = { "interval", "timeout", "start_delay", }; - CRM_DEV_ASSERT(action->rsc != NULL); + CRM_CHECK(action->rsc != NULL, return); if(xml_obj != NULL) { value = crm_element_value(xml_obj, "prereq"); } if(value == NULL && safe_str_eq(action->task, CRMD_ACTION_START)) { value = g_hash_table_lookup( action->rsc->parameters, "start_prereq"); } if(value == NULL && safe_str_neq(action->task, CRMD_ACTION_START)) { /* todo: integrate stop as an option? */ action->needs = rsc_req_nothing; value = "nothing (default)"; } else if(safe_str_eq(value, "nothing")) { action->needs = rsc_req_nothing; } else if(safe_str_eq(value, "quorum")) { action->needs = rsc_req_quorum; } else if(safe_str_eq(value, "fencing")) { action->needs = rsc_req_stonith; } else if(data_set->no_quorum_policy == no_quorum_ignore) { action->needs = rsc_req_nothing; value = "nothing (default)"; } else if(data_set->no_quorum_policy == no_quorum_freeze && data_set->stonith_enabled) { action->needs = rsc_req_stonith; value = "fencing (default)"; } else { action->needs = rsc_req_quorum; value = "quorum (default)"; } crm_debug_2("\tAction %s requires: %s", action->task, value); value = NULL; if(xml_obj != NULL) { value = crm_element_value(xml_obj, "on_fail"); } #if CRM_DEPRECATED_SINCE_2_0_2 if(value == NULL && safe_str_eq(action->task, CRMD_ACTION_STOP)) { value = g_hash_table_lookup( action->rsc->parameters, "on_stopfail"); if(value != NULL) { crm_err("The \"on_stopfail\" attribute in %s is deprecated", action->rsc->id); crm_err("Please use specify the \"on_fail\" attribute on the" " \"stop\" operation instead"); } } #endif if(value == NULL) { } else if(safe_str_eq(value, "block")) { action->on_fail = action_fail_block; } else if(safe_str_eq(value, "fence")) { action->on_fail = action_fail_fence; value = "node fencing"; } else if(safe_str_eq(value, "ignore")) { action->on_fail = action_fail_ignore; value = "ignore"; } else if(safe_str_eq(value, "migrate")) { action->on_fail = action_fail_migrate; value = "force migration"; } else if(safe_str_eq(value, "stop")) { action->fail_role = RSC_ROLE_STOPPED; value = "stop resource"; } else if(safe_str_eq(value, "restart") || safe_str_eq(value, "nothing")) { action->on_fail = action_fail_recover; value = "restart (and possibly migrate)"; } else { pe_err("Resource %s: Unknown failure type (%s)", action->rsc->id, value); value = NULL; } /* defaults */ if(value == NULL && safe_str_eq(action->task, CRMD_ACTION_STOP)) { if(data_set->stonith_enabled) { action->on_fail = action_fail_fence; value = "resource fence (default)"; } else { action->on_fail = action_fail_block; value = "resource block (default)"; } } else if(value == NULL) { action->on_fail = action_fail_recover; value = "restart (and possibly migrate) (default)"; } crm_debug_2("\t%s failure handling: %s", action->task, value); value = NULL; if(xml_obj != NULL) { value = crm_element_value(xml_obj, "role_after_failure"); } if(value != NULL && action->fail_role == RSC_ROLE_UNKNOWN) { action->fail_role = text2role(value); } /* defaults */ if(action->fail_role == RSC_ROLE_UNKNOWN) { if(safe_str_eq(action->task, CRMD_ACTION_PROMOTE)) { action->fail_role = RSC_ROLE_SLAVE; } else { action->fail_role = RSC_ROLE_STARTED; } } crm_debug_2("\t%s failure results in: %s", action->task, role2text(action->fail_role)); if(xml_obj == NULL) { return; } for(;lpc < DIMOF(fields); lpc++) { value = crm_element_value(xml_obj, fields[lpc]); if(value != NULL) { int tmp_i = crm_get_msec(value); char *tmp_ms = NULL; if(tmp_i < 0) { tmp_i = 0; } tmp_ms = crm_itoa(tmp_i); g_hash_table_insert( action->extra, crm_strdup(fields[lpc]), tmp_ms); } } /* if(safe_str_eq(native_data->agent->class, "stonith")) { */ /* if(rsc->start_needs == rsc_req_stonith) { */ /* pe_err("Stonith resources (eg. %s) cannot require" */ /* " fencing to start", rsc->id); */ /* } */ /* rsc->start_needs = rsc_req_quorum; */ /* } */ } crm_data_t * find_rsc_op_entry(resource_t *rsc, const char *key) { const char *name = NULL; const char *interval = NULL; char *match_key = NULL; crm_data_t *op = NULL; xml_child_iter_filter( rsc->ops_xml, operation, "op", name = crm_element_value(operation, "name"); interval = crm_element_value(operation, "interval"); match_key = generate_op_key(rsc->id,name,crm_get_msec(interval)); crm_debug_2("Matching %s with %s", key, match_key); if(safe_str_eq(key, match_key)) { op = operation; } crm_free(match_key); if(op != NULL) { break; } ); crm_debug_2("No matching for %s", key); return op; } const char * fail2text(enum action_fail_response fail) { const char *result = ""; switch(fail) { case action_fail_ignore: result = "ignore"; break; case action_fail_block: result = "block"; break; case action_fail_recover: result = "recover"; break; case action_fail_migrate: result = "migrate"; break; case action_fail_fence: result = "fence"; break; } return result; } const char * strength2text(enum con_strength strength) { const char *result = ""; switch(strength) { case pecs_ignore: result = "ignore"; break; case pecs_must: result = XML_STRENGTH_VAL_MUST; break; case pecs_must_not: result = XML_STRENGTH_VAL_MUSTNOT; break; case pecs_startstop: result = "start/stop"; break; } return result; } const char * ordering_type2text(enum pe_ordering type) { const char *result = ""; switch(type) { case pe_ordering_manditory: result = "manditory"; break; case pe_ordering_restart: result = "restart"; break; case pe_ordering_recover: result = "recover"; break; case pe_ordering_optional: result = "optional"; break; case pe_ordering_postnotify: result = "post_notify"; break; } return result; } enum action_tasks text2task(const char *task) { if(safe_str_eq(task, CRMD_ACTION_STOP)) { return stop_rsc; } else if(safe_str_eq(task, CRMD_ACTION_STOPPED)) { return stopped_rsc; } else if(safe_str_eq(task, CRMD_ACTION_START)) { return start_rsc; } else if(safe_str_eq(task, CRMD_ACTION_STARTED)) { return started_rsc; } else if(safe_str_eq(task, CRM_OP_SHUTDOWN)) { return shutdown_crm; } else if(safe_str_eq(task, CRM_OP_FENCE)) { return stonith_node; } else if(safe_str_eq(task, CRMD_ACTION_MON)) { return monitor_rsc; } else if(safe_str_eq(task, CRMD_ACTION_NOTIFY)) { return action_notify; } else if(safe_str_eq(task, CRMD_ACTION_NOTIFIED)) { return action_notified; } else if(safe_str_eq(task, CRMD_ACTION_PROMOTE)) { return action_promote; } else if(safe_str_eq(task, CRMD_ACTION_DEMOTE)) { return action_demote; } else if(safe_str_eq(task, CRMD_ACTION_PROMOTED)) { return action_promoted; } else if(safe_str_eq(task, CRMD_ACTION_DEMOTED)) { return action_demoted; } else if(safe_str_eq(task, CRMD_ACTION_CANCEL)) { return no_action; } else if(safe_str_eq(task, CRMD_ACTION_DELETE)) { return no_action; } else if(safe_str_eq(task, CRMD_ACTION_STATUS)) { return no_action; } else if(safe_str_eq(task, CRM_OP_PROBED)) { return no_action; } else if(safe_str_eq(task, CRM_OP_LRM_REFRESH)) { return no_action; } pe_err("Unsupported action: %s", task); return no_action; } const char * task2text(enum action_tasks task) { const char *result = ""; switch(task) { case no_action: result = "no_action"; break; case stop_rsc: result = CRMD_ACTION_STOP; break; case stopped_rsc: result = CRMD_ACTION_STOPPED; break; case start_rsc: result = CRMD_ACTION_START; break; case started_rsc: result = CRMD_ACTION_STARTED; break; case shutdown_crm: result = CRM_OP_SHUTDOWN; break; case stonith_node: result = CRM_OP_FENCE; break; case monitor_rsc: result = CRMD_ACTION_MON; break; case action_notify: result = CRMD_ACTION_NOTIFY; break; case action_notified: result = CRMD_ACTION_NOTIFIED; break; case action_promote: result = CRMD_ACTION_PROMOTE; break; case action_promoted: result = CRMD_ACTION_PROMOTED; break; case action_demote: result = CRMD_ACTION_DEMOTE; break; case action_demoted: result = CRMD_ACTION_DEMOTED; break; } return result; } const char * role2text(enum rsc_role_e role) { - CRM_DEV_ASSERT(role >= RSC_ROLE_UNKNOWN); - CRM_DEV_ASSERT(role < RSC_ROLE_MAX); + CRM_CHECK(role >= RSC_ROLE_UNKNOWN, return RSC_ROLE_UNKNOWN_S); + CRM_CHECK(role < RSC_ROLE_MAX, return RSC_ROLE_UNKNOWN_S); switch(role) { case RSC_ROLE_UNKNOWN: return RSC_ROLE_UNKNOWN_S; case RSC_ROLE_STOPPED: return RSC_ROLE_STOPPED_S; case RSC_ROLE_STARTED: return RSC_ROLE_STARTED_S; case RSC_ROLE_SLAVE: return RSC_ROLE_SLAVE_S; case RSC_ROLE_MASTER: return RSC_ROLE_MASTER_S; } return RSC_ROLE_UNKNOWN_S; } enum rsc_role_e text2role(const char *role) { if(safe_str_eq(role, RSC_ROLE_STOPPED_S)) { return RSC_ROLE_STOPPED; } else if(safe_str_eq(role, RSC_ROLE_STARTED_S)) { return RSC_ROLE_STARTED; } else if(safe_str_eq(role, RSC_ROLE_SLAVE_S)) { return RSC_ROLE_SLAVE; } else if(safe_str_eq(role, RSC_ROLE_MASTER_S)) { return RSC_ROLE_MASTER; } else if(safe_str_eq(role, RSC_ROLE_UNKNOWN_S)) { return RSC_ROLE_UNKNOWN; } crm_err("Unknown role: %s", role); return RSC_ROLE_UNKNOWN; } void print_node(const char *pre_text, node_t *node, gboolean details) { if(node == NULL) { crm_debug_4("%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } crm_debug_4("%s%s%sNode %s: (weight=%d, fixed=%s)", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", node->details==NULL?"error ":node->details->online?"":"Unavailable/Unclean ", node->details->uname, node->weight, node->fixed?"True":"False"); if(details && node != NULL && node->details != NULL) { char *pe_mutable = crm_strdup("\t\t"); crm_debug_4("\t\t===Node Attributes"); g_hash_table_foreach(node->details->attrs, print_str_str, pe_mutable); crm_free(pe_mutable); crm_debug_4("\t\t=== Resources"); slist_iter( rsc, resource_t, node->details->running_rsc, lpc, print_resource(LOG_DEBUG_4, "\t\t", rsc, FALSE); ); } } /* * Used by the HashTable for-loop */ void print_str_str(gpointer key, gpointer value, gpointer user_data) { crm_debug_4("%s%s %s ==> %s", user_data==NULL?"":(char*)user_data, user_data==NULL?"":": ", (char*)key, (char*)value); } void print_color_details(const char *pre_text, struct color_shared_s *color, gboolean details) { if(color == NULL) { crm_debug_4("%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } crm_debug_4("%s%sColor %d: node=%s (from %d candidates)", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", color->id, color->chosen_node==NULL?"":color->chosen_node->details->uname, g_list_length(color->candidate_nodes)); if(details) { slist_iter(node, node_t, color->candidate_nodes, lpc, print_node("\t", node, FALSE)); } } void print_color(const char *pre_text, color_t *color, gboolean details) { if(color == NULL) { crm_debug_4("%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } crm_debug_4("%s%sColor %d: (weight=%d, node=%s, possible=%d)", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", color->id, color->local_weight, safe_val5("",color,details,chosen_node,details,uname), g_list_length(color->details->candidate_nodes)); if(details) { print_color_details("\t", color->details, details); } } void print_rsc_to_node(const char *pre_text, rsc_to_node_t *cons, gboolean details) { if(cons == NULL) { crm_debug_4("%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } crm_debug_4("%s%s%s Constraint %s (%p) - %d nodes:", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", "rsc_to_node", cons->id, cons, g_list_length(cons->node_list_rh)); if(details == FALSE) { crm_debug_4("\t%s (node placement rule)", safe_val3(NULL, cons, rsc_lh, id)); slist_iter( node, node_t, cons->node_list_rh, lpc, print_node("\t\t-->", node, FALSE) ); } } void print_rsc_colocation(const char *pre_text, rsc_colocation_t *cons, gboolean details) { if(cons == NULL) { crm_debug_4("%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } crm_debug_4("%s%s%s Constraint %s (%p):", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", XML_CONS_TAG_RSC_DEPEND, cons->id, cons); if(details == FALSE) { crm_debug_4("\t%s --> %s, %s", safe_val3(NULL, cons, rsc_lh, id), safe_val3(NULL, cons, rsc_rh, id), strength2text(cons->strength)); } } void print_resource( int log_level, const char *pre_text, resource_t *rsc, gboolean details) { long options = pe_print_log; if(rsc == NULL) { - crm_debug_4("%s%s: ", - pre_text==NULL?"":pre_text, - pre_text==NULL?"":": "); + crm_log_maybe(log_level-1, "%s%s: ", + pre_text==NULL?"":pre_text, + pre_text==NULL?"":": "); return; } if(details) { options |= pe_print_details; } rsc->fns->print(rsc, pre_text, options, &log_level); } #define util_log(fmt...) do_crm_log(log_level, __FILE__, __FUNCTION__, fmt) void log_action(unsigned int log_level, const char *pre_text, action_t *action, gboolean details) { const char *node_uname = NULL; const char *node_uuid = NULL; if(action == NULL) { util_log("%s%s: ", pre_text==NULL?"":pre_text, pre_text==NULL?"":": "); return; } if(action->pseudo) { node_uname = NULL; node_uuid = NULL; } else if(action->node != NULL) { node_uname = action->node->details->uname; node_uuid = action->node->details->id; } else { node_uname = ""; node_uuid = NULL; } switch(text2task(action->task)) { case stonith_node: case shutdown_crm: crm_log_maybe(log_level, "%s%s%sAction %d: %s%s%s%s%s%s", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", action->pseudo?"Pseduo ":action->optional?"Optional ":action->runnable?action->processed?"":"(Provisional) ":"!!Non-Startable!! ", action->id, action->uuid, node_uname?"\ton ":"", node_uname?node_uname:"", node_uuid?"\t\t(":"", node_uuid?node_uuid:"", node_uuid?")":""); break; default: crm_log_maybe(log_level, "%s%s%sAction %d: %s %s%s%s%s%s%s", pre_text==NULL?"":pre_text, pre_text==NULL?"":": ", action->optional?"Optional ":action->pseudo?"Pseduo ":action->runnable?action->processed?"":"(Provisional) ":"!!Non-Startable!! ", action->id, action->uuid, safe_val3("", action, rsc, id), node_uname?"\ton ":"", node_uname?node_uname:"", node_uuid?"\t\t(":"", node_uuid?node_uuid:"", node_uuid?")":""); break; } if(details) { crm_log_maybe(log_level+1, "\t\t====== Preceeding Actions"); slist_iter( other, action_wrapper_t, action->actions_before, lpc, log_action(log_level+1, "\t\t", other->action, FALSE); ); #if 1 crm_log_maybe(log_level+1, "\t\t====== Subsequent Actions"); slist_iter( other, action_wrapper_t, action->actions_after, lpc, log_action(log_level+1, "\t\t", other->action, FALSE); ); #endif crm_log_maybe(log_level+1, "\t\t====== End"); } else { crm_log_maybe(log_level, "\t\t(seen=%d, before=%d, after=%d)", action->seen_count, g_list_length(action->actions_before), g_list_length(action->actions_after)); } } void pe_free_nodes(GListPtr nodes) { GListPtr iterator = nodes; while(iterator != NULL) { node_t *node = (node_t*)iterator->data; struct node_shared_s *details = node->details; iterator = iterator->next; crm_debug_5("deleting node"); crm_debug_5("%s is being deleted", details->uname); print_node("delete", node, FALSE); if(details != NULL) { if(details->attrs != NULL) { g_hash_table_destroy(details->attrs); } pe_free_shallow_adv(details->running_rsc, FALSE); crm_free(details); } crm_free(node); } if(nodes != NULL) { g_list_free(nodes); } } void pe_free_colors(GListPtr colors) { GListPtr iterator = colors; while(iterator != NULL) { color_t *color = (color_t *)iterator->data; struct color_shared_s *details = color->details; iterator = iterator->next; if(details != NULL) { pe_free_shallow(details->candidate_nodes); pe_free_shallow_adv(details->allocated_resources, FALSE); crm_free(details->chosen_node); crm_free(details); } crm_free(color); } if(colors != NULL) { g_list_free(colors); } } void pe_free_shallow(GListPtr alist) { pe_free_shallow_adv(alist, TRUE); } void pe_free_shallow_adv(GListPtr alist, gboolean with_data) { GListPtr item; GListPtr item_next = alist; while(item_next != NULL) { item = item_next; item_next = item_next->next; if(with_data) { /* crm_debug_5("freeing %p", item->data); */ crm_free(item->data); } item->data = NULL; item->next = NULL; g_list_free(item); } } void pe_free_resources(GListPtr resources) { resource_t *rsc = NULL; GListPtr iterator = resources; while(iterator != NULL) { iterator = iterator; rsc = (resource_t *)iterator->data; iterator = iterator->next; rsc->fns->free(rsc); } if(resources != NULL) { g_list_free(resources); } } void pe_free_actions(GListPtr actions) { GListPtr iterator = actions; while(iterator != NULL) { action_t *action = (action_t *)iterator->data; iterator = iterator->next; pe_free_shallow(action->actions_before);/* action_warpper_t* */ pe_free_shallow(action->actions_after); /* action_warpper_t* */ g_hash_table_destroy(action->extra); crm_free(action->uuid); crm_free(action); } if(actions != NULL) { g_list_free(actions); } } void pe_free_ordering(GListPtr constraints) { GListPtr iterator = constraints; while(iterator != NULL) { order_constraint_t *order = iterator->data; iterator = iterator->next; crm_free(order->lh_action_task); crm_free(order->rh_action_task); crm_free(order); } if(constraints != NULL) { g_list_free(constraints); } } void pe_free_rsc_colocation(rsc_colocation_t *cons) { if(cons != NULL) { crm_debug_4("Freeing constraint %s (%p)", cons->id, cons); crm_free(cons); } } void pe_free_rsc_to_node(rsc_to_node_t *cons) { if(cons != NULL) { pe_free_shallow(cons->node_list_rh); crm_free(cons); } } GListPtr find_actions(GListPtr input, const char *key, node_t *on_node) { GListPtr result = NULL; - CRM_DEV_ASSERT(key != NULL); + CRM_CHECK(key != NULL, return NULL); slist_iter( action, action_t, input, lpc, crm_debug_5("Matching %s against %s", key, action->uuid); if(safe_str_neq(key, action->uuid)) { continue; } else if(on_node == NULL) { result = g_list_append(result, action); } else if(action->node == NULL) { /* skip */ crm_debug_2("While looking for %s action on %s, " "found an unallocated one. Assigning" " it to the requested node...", key, on_node->details->uname); action->node = on_node; result = g_list_append(result, action); } else if(safe_str_eq(on_node->details->id, action->node->details->id)) { result = g_list_append(result, action); } ); return result; } GListPtr find_actions_exact(GListPtr input, const char *key, node_t *on_node) { GListPtr result = NULL; - CRM_DEV_ASSERT(key != NULL); + CRM_CHECK(key != NULL, return NULL); slist_iter( action, action_t, input, lpc, crm_debug_5("Matching %s against %s", key, action->uuid); if(safe_str_neq(key, action->uuid)) { crm_debug_3("Key mismatch: %s vs. %s", key, action->uuid); continue; } else if(on_node == NULL || action->node == NULL) { crm_debug_3("on_node=%p, action->node=%p", on_node, action->node); continue; } else if(safe_str_eq(on_node->details->id, action->node->details->id)) { result = g_list_append(result, action); } crm_debug_2("Node mismatch: %s vs. %s", on_node->details->id, action->node->details->id); ); return result; } void set_id(crm_data_t * xml_obj, const char *prefix, int child) { int id_len = 0; gboolean use_prefix = TRUE; gboolean use_child = TRUE; char *new_id = NULL; const char *id = crm_element_value(xml_obj, XML_ATTR_ID); id_len = 1 + strlen(id); if(child > 999) { pe_err("Are you insane?!?" " The CRM does not support > 1000 children per resource"); return; } else if(child < 0) { use_child = FALSE; } else { id_len += 4; /* child */ } if(prefix == NULL || safe_str_eq(id, prefix)) { use_prefix = FALSE; } else { id_len += (1 + strlen(prefix)); } crm_malloc0(new_id, id_len); if(use_child) { snprintf(new_id, id_len, "%s%s%s:%d", use_prefix?prefix:"", use_prefix?":":"", id, child); } else { snprintf(new_id, id_len, "%s%s%s", use_prefix?prefix:"", use_prefix?":":"", id); } crm_xml_add(xml_obj, XML_ATTR_ID, new_id); crm_free(new_id); } int merge_weights(int w1, int w2) { int result = w1 + w2; if(w1 <= -INFINITY || w2 <= -INFINITY) { if(w1 >= INFINITY || w2 >= INFINITY) { crm_debug_2("-INFINITY + INFINITY == -INFINITY"); } return -INFINITY; } else if(w1 >= INFINITY || w2 >= INFINITY) { return INFINITY; } /* detect wrap-around */ if(result > 0) { if(w1 <= 0 && w2 < 0) { result = -INFINITY; } } else if(w1 > 0 && w2 > 0) { result = INFINITY; } /* detect +/- INFINITY */ if(result >= INFINITY) { result = INFINITY; } else if(result <= -INFINITY) { result = -INFINITY; } return result; } int char2score(const char *score) { int score_f = 0; if(score == NULL) { } else if(safe_str_eq(score, MINUS_INFINITY_S)) { score_f = -INFINITY; } else if(safe_str_eq(score, INFINITY_S)) { score_f = INFINITY; } else if(safe_str_eq(score, "+"INFINITY_S)) { score_f = INFINITY; } else { score_f = crm_parse_int(score, NULL); if(score_f > 0 && score_f > INFINITY) { score_f = INFINITY; } else if(score_f < 0 && score_f < -INFINITY) { score_f = -INFINITY; } } return score_f; } rsc_to_node_t * rsc2node_new(const char *id, resource_t *rsc, int node_weight, node_t *foo_node, pe_working_set_t *data_set) { rsc_to_node_t *new_con = NULL; if(rsc == NULL || id == NULL) { pe_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->role_filter = RSC_ROLE_UNKNOWN; if(foo_node != NULL) { node_t *copy = node_copy(foo_node); copy->weight = node_weight; new_con->node_list_rh = g_list_append(NULL, copy); } else { - CRM_DEV_ASSERT(node_weight == 0); + CRM_CHECK(node_weight == 0, return NULL); } data_set->placement_constraints = g_list_append( data_set->placement_constraints, new_con); rsc->rsc_location = g_list_append( rsc->rsc_location, new_con); } return new_con; } diff --git a/crm/tengine/actions.c b/crm/tengine/actions.c index 8fa8eb6a9e..133da2e811 100644 --- a/crm/tengine/actions.c +++ b/crm/tengine/actions.c @@ -1,483 +1,477 @@ -/* $Id: actions.c,v 1.17 2006/03/08 15:49:40 andrew Exp $ */ +/* $Id: actions.c,v 1.18 2006/03/18 17:23:48 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 char *te_uuid = NULL; IPC_Channel *crm_ch = NULL; void send_rsc_command(crm_action_t *action); extern crm_action_timer_t *transition_timer; static void te_start_action_timer(crm_action_t *action) { crm_malloc0(action->timer, sizeof(crm_action_timer_t)); action->timer->timeout = action->timeout; action->timer->reason = timeout_action_warn; action->timer->action = action; action->timer->source_id = Gmain_timeout_add( action->timer->timeout, action_timer_callback, (void*)action->timer); CRM_ASSERT(action->timer->source_id != 0); } static gboolean te_pseudo_action(crm_graph_t *graph, crm_action_t *pseudo) { crm_debug("Event handler: action %d executed", pseudo->id); pseudo->confirmed = TRUE; update_graph(graph, pseudo); trigger_graph(); return TRUE; } void send_stonith_update(stonith_ops_t * op) { enum cib_errors rc = cib_ok; const char *target = op->node_name; const char *uuid = op->node_uuid; /* zero out the node-status & remove all LRM status info */ crm_data_t *node_state = create_xml_node(NULL, XML_CIB_TAG_STATE); - CRM_DEV_ASSERT(op->node_name != NULL); - CRM_DEV_ASSERT(op->node_uuid != NULL); + CRM_CHECK(op->node_name != NULL, return); + CRM_CHECK(op->node_uuid != NULL, return); crm_xml_add(node_state, XML_ATTR_UUID, uuid); crm_xml_add(node_state, XML_ATTR_UNAME, target); crm_xml_add(node_state, XML_CIB_ATTR_HASTATE, DEADSTATUS); crm_xml_add(node_state, XML_CIB_ATTR_INCCM, XML_BOOLEAN_NO); crm_xml_add(node_state, XML_CIB_ATTR_CRMDSTATE, OFFLINESTATUS); crm_xml_add(node_state, XML_CIB_ATTR_JOINSTATE, CRMD_JOINSTATE_DOWN); crm_xml_add(node_state, XML_CIB_ATTR_EXPSTATE, CRMD_JOINSTATE_DOWN); crm_xml_add(node_state, XML_CIB_ATTR_REPLACE, XML_CIB_TAG_LRM); crm_xml_add(node_state, "origin", __FUNCTION__); rc = te_cib_conn->cmds->update( te_cib_conn, XML_CIB_TAG_STATUS, node_state, NULL, cib_quorum_override|cib_scope_local); if(rc < cib_ok) { crm_err("CIB update failed: %s", cib_error2string(rc)); abort_transition( INFINITY, tg_shutdown, "CIB update failed", node_state); } else { /* delay processing the trigger until the update completes */ add_cib_op_callback(rc, FALSE, NULL, cib_fencing_updated); } free_xml(node_state); return; } static gboolean te_fence_node(crm_graph_t *graph, crm_action_t *action) { char *key = NULL; const char *id = NULL; const char *uuid = NULL; const char *target = NULL; const char *type = NULL; stonith_ops_t * st_op = NULL; id = ID(action->xml); target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); uuid = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID); type = g_hash_table_lookup(action->params, "stonith_action"); - CRM_DEV_ASSERT(id != NULL); - CRM_DEV_ASSERT(uuid != NULL); - CRM_DEV_ASSERT(type != NULL); - CRM_DEV_ASSERT(target != NULL); + CRM_CHECK(id != NULL, return FALSE); + CRM_CHECK(uuid != NULL, return FALSE); + CRM_CHECK(type != NULL, return FALSE); + CRM_CHECK(target != NULL, return FALSE); if(id == NULL || uuid == NULL || target == NULL) { /* error */ te_log_action(LOG_ERR, "Corrupted command (id=%s): no node", crm_str(id)); return FALSE; } te_log_action(LOG_INFO, "Executing %s fencing operation (%s) on %s (timeout=%d)", type, id, target, transition_graph->transition_timeout / 2); crm_malloc0(st_op, sizeof(stonith_ops_t)); if(safe_str_eq(type, "poweroff")) { st_op->optype = POWEROFF; } else { st_op->optype = RESET; } st_op->timeout = transition_graph->transition_timeout / 2; st_op->node_name = crm_strdup(target); st_op->node_uuid = crm_strdup(uuid); key = generate_transition_key(transition_graph->id, te_uuid); st_op->private_data = crm_concat(id, key, ';'); crm_free(key); if(stonithd_input_IPC_channel() == NULL) { crm_err("Cannot fence %s: stonith not available", target); return FALSE; } else if (ST_OK != stonithd_node_fence( st_op )) { crm_err("Cannot fence %s: stonithd_node_fence() call failed ", target); return FALSE; } return TRUE; } static gboolean te_crm_command(crm_graph_t *graph, crm_action_t *action) { char *value = NULL; char *counter = NULL; HA_Message *cmd = NULL; const char *id = NULL; const char *task = NULL; const char *on_node = NULL; gboolean ret = TRUE; id = ID(action->xml); task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); on_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); - CRM_DEV_ASSERT(on_node != NULL && strlen(on_node) != 0); - if(crm_assert_failed) { - /* error */ - te_log_action(LOG_ERR, "Corrupted command (id=%s) %s: no node", - crm_str(id), crm_str(task)); - return FALSE; - } + CRM_CHECK(on_node != NULL && strlen(on_node) != 0, + te_log_action(LOG_ERR, "Corrupted command (id=%s) %s: no node", + crm_str(id), crm_str(task)); + return FALSE); te_log_action(LOG_INFO, "Executing crm-event (%s): %s on %s", crm_str(id), crm_str(task), on_node); cmd = create_request(task, NULL, on_node, CRM_SYSTEM_CRMD, CRM_SYSTEM_TENGINE, NULL); counter = generate_transition_key(transition_graph->id, te_uuid); crm_xml_add(cmd, XML_ATTR_TRANSITION_KEY, counter); ret = send_ipc_message(crm_ch, cmd); crm_free(counter); value = g_hash_table_lookup(action->params, XML_ATTR_TE_NOWAIT); if(ret == FALSE) { crm_err("Action %d failed: send", action->id); return FALSE; } else if(crm_is_true(value)) { crm_info("Skipping wait for %d", action->id); action->confirmed = TRUE; update_graph(graph, action); trigger_graph(); } else if(ret && action->timeout > 0) { crm_debug("Setting timer for action %d",action->id); action->timer->reason = timeout_action_warn; te_start_action_timer(action); } return TRUE; } static gboolean te_rsc_command(crm_graph_t *graph, crm_action_t *action) { /* never overwrite stop actions in the CIB with * anything other than completed results * * Writing pending stops makes it look like the * resource is running again */ const char *task = NULL; const char *on_node = NULL; action->executed = FALSE; on_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); - CRM_DEV_ASSERT(on_node != NULL && strlen(on_node) != 0); - if(crm_assert_failed) { - /* error */ - te_log_action(LOG_ERR, "Corrupted command(id=%s) %s: no node", - ID(action->xml), crm_str(task)); - return FALSE; - } + CRM_CHECK(on_node != NULL && strlen(on_node) != 0, + te_log_action(LOG_ERR, "Corrupted command(id=%s) %s: no node", + ID(action->xml), crm_str(task)); + return FALSE); send_rsc_command(action); return TRUE; } gboolean cib_action_update(crm_action_t *action, int status) { char *code = NULL; crm_data_t *fragment = NULL; crm_data_t *state = NULL; crm_data_t *rsc = NULL; crm_data_t *xml_op = NULL; char *op_id = NULL; enum cib_errors rc = cib_ok; const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); const char *rsc_id = crm_element_value(action->xml, XML_LRM_ATTR_RSCID); const char *target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); const char *task_uuid = crm_element_value( action->xml, XML_LRM_ATTR_TASK_KEY); const char *target_uuid = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID); int call_options = cib_quorum_override|cib_scope_local; if(status == LRM_OP_TIMEOUT) { if(crm_element_value(action->xml, XML_LRM_ATTR_RSCID) != NULL) { crm_warn("%s: %s %s on %s timed out", crm_element_name(action->xml), task_uuid, rsc_id, target); } else { crm_warn("%s: %s on %s timed out", crm_element_name(action->xml), task_uuid, target); } } code = crm_itoa(status); /* update the CIB */ fragment = NULL; state = create_xml_node(NULL, XML_CIB_TAG_STATE); crm_xml_add(state, XML_ATTR_UUID, target_uuid); crm_xml_add(state, XML_ATTR_UNAME, target); rsc = create_xml_node(state, XML_CIB_TAG_LRM); rsc = create_xml_node(rsc, XML_LRM_TAG_RESOURCES); rsc = create_xml_node(rsc, XML_LRM_TAG_RESOURCE); xml_op = create_xml_node(rsc,XML_LRM_TAG_RSC_OP); crm_xml_add(rsc, XML_ATTR_ID, rsc_id); crm_xml_add(xml_op, XML_ATTR_ID, task); op_id = generate_op_key(rsc_id, task, action->interval); crm_xml_add(xml_op, XML_ATTR_ID, op_id); crm_free(op_id); crm_xml_add(xml_op, XML_LRM_ATTR_TASK, task); crm_xml_add(rsc, XML_LRM_ATTR_RSCSTATE, get_rsc_state(task, status)); crm_xml_add(xml_op, XML_LRM_ATTR_OPSTATUS, code); crm_xml_add(xml_op, XML_LRM_ATTR_CALLID, "-1"); crm_xml_add(xml_op, XML_LRM_ATTR_RC, code); crm_xml_add(xml_op, "origin", __FUNCTION__); crm_free(code); code = generate_transition_key(transition_graph->id, te_uuid); crm_xml_add(xml_op, XML_ATTR_TRANSITION_KEY, code); crm_free(code); code = generate_transition_magic( crm_element_value(xml_op, XML_ATTR_TRANSITION_KEY), status, status); crm_xml_add(xml_op, XML_ATTR_TRANSITION_MAGIC, code); crm_free(code); set_node_tstamp(xml_op); fragment = create_cib_fragment(state, XML_CIB_TAG_STATUS); crm_debug_3("Updating CIB with \"%s\" (%s): %s %s on %s", status<0?"new action":XML_ATTR_TIMEOUT, crm_element_name(action->xml), crm_str(task), rsc_id, target); rc = te_cib_conn->cmds->update( te_cib_conn, XML_CIB_TAG_STATUS, fragment, NULL, call_options); crm_debug("Updating CIB with %s action %d: %s %s on %s (call_id=%d)", op_status2text(status), action->id, task_uuid, rsc_id, target, rc); crm_debug_2("Waiting for callback id: %d", rc); add_cib_op_callback(rc, FALSE, action, cib_action_updated); free_xml(fragment); free_xml(state); action->sent_update = TRUE; if(rc < cib_ok) { return FALSE; } return TRUE; } void send_rsc_command(crm_action_t *action) { HA_Message *cmd = NULL; crm_data_t *rsc_op = NULL; char *counter = crm_itoa(transition_graph->id); const char *task = NULL; const char *value = NULL; const char *rsc_id = NULL; const char *on_node = NULL; const char *task_uuid = NULL; CRM_ASSERT(action != NULL); CRM_ASSERT(action->xml != NULL); rsc_op = action->xml; task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); task_uuid = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY); rsc_id = crm_element_value(rsc_op, XML_LRM_ATTR_RSCID); on_node = crm_element_value(rsc_op, XML_LRM_ATTR_TARGET); counter = generate_transition_key(transition_graph->id, te_uuid); crm_xml_add(rsc_op, XML_ATTR_TRANSITION_KEY, counter); crm_info("Initiating action %d: %s on %s", action->id, task_uuid, on_node); crm_free(counter); if(rsc_op != NULL) { crm_log_xml_debug_2(rsc_op, "Performing"); } cmd = create_request(CRM_OP_INVOKE_LRM, rsc_op, on_node, CRM_SYSTEM_LRMD, CRM_SYSTEM_TENGINE, NULL); #if 1 send_ipc_message(crm_ch, cmd); #else /* test the TE timer/recovery code */ if((action->id % 11) == 0) { crm_err("Faking lost action %d: %s", action->id, task_uuid); } else { send_ipc_message(crm_ch, cmd); } #endif action->executed = TRUE; value = g_hash_table_lookup(action->params, XML_ATTR_TE_NOWAIT); if(crm_is_true(value)) { crm_debug("Skipping wait for %d", action->id); action->confirmed = TRUE; update_graph(transition_graph, action); trigger_graph(); } else if(action->timeout > 0) { int action_timeout = 2 * action->timeout; crm_debug_3("Setting timer for action %s", task_uuid); if(transition_graph->transition_timeout < action_timeout) { crm_debug("Action %d:" " Increasing transition %d timeout to %d", action->id, transition_graph->id, transition_graph->transition_timeout); transition_graph->transition_timeout = action_timeout; } te_start_action_timer(action); } } crm_graph_functions_t te_graph_fns = { te_pseudo_action, te_rsc_command, te_crm_command, te_fence_node }; void notify_crmd(crm_graph_t *graph) { HA_Message *cmd = NULL; int log_level = LOG_DEBUG; const char *op = CRM_OP_TEABORT; int pending_callbacks = num_cib_op_callbacks(); stop_te_timer(transition_timer); if(pending_callbacks != 0) { crm_warn("Delaying completion until all CIB updates complete"); return; } - CRM_DEV_ASSERT(graph->complete); + CRM_CHECK(graph->complete, return); switch(graph->completion_action) { case tg_stop: op = CRM_OP_TECOMPLETE; log_level = LOG_INFO; break; case tg_abort: case tg_restart: op = CRM_OP_TEABORT; break; case tg_shutdown: crm_info("Exiting after transition"); exit(LSB_EXIT_OK); } te_log_action(log_level, "Transition %d status: %s - %s", graph->id, op, graph->abort_reason); print_graph(log_level, graph); cmd = create_request( op, NULL, NULL, CRM_SYSTEM_DC, CRM_SYSTEM_TENGINE, NULL); if(graph->abort_reason != NULL) { ha_msg_add(cmd, "message", graph->abort_reason); } send_ipc_message(crm_ch, cmd); graph->abort_reason = NULL; graph->completion_action = tg_restart; } diff --git a/crm/tengine/callbacks.c b/crm/tengine/callbacks.c index 4fc369d16e..780ea6ebeb 100644 --- a/crm/tengine/callbacks.c +++ b/crm/tengine/callbacks.c @@ -1,540 +1,535 @@ -/* $Id: callbacks.c,v 1.71 2006/03/16 23:33:21 andrew Exp $ */ +/* $Id: callbacks.c,v 1.72 2006/03/18 17:23:48 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 void te_update_confirm(const char *event, HA_Message *msg); void te_update_diff(const char *event, HA_Message *msg); crm_data_t *need_abort(crm_data_t *update); void cib_fencing_updated(const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data); extern char *te_uuid; gboolean shuttingdown = FALSE; crm_graph_t *transition_graph; GTRIGSource *transition_trigger = NULL; crm_action_timer_t *transition_timer = NULL; static gboolean start_global_timer(crm_action_timer_t *timer, int timeout) { CRM_ASSERT(timer != NULL); - CRM_DEV_ASSERT(timer > 0); - CRM_DEV_ASSERT(timer->source_id == 0); + CRM_CHECK(timer > 0, return FALSE); + CRM_CHECK(timer->source_id == 0, return FALSE); if(timeout <= 0) { crm_err("Tried to start timer with period: %d", timeout); } else if(timer->source_id == 0) { crm_debug("Starting abort timer: %dms", timeout); timer->timeout = timeout; timer->source_id = Gmain_timeout_add( timeout, global_timer_callback, (void*)timer); CRM_ASSERT(timer->source_id != 0); return TRUE; } else { crm_err("Timer is already active with period: %d", timer->timeout); } return FALSE; } void te_update_diff(const char *event, HA_Message *msg) { int rc = -1; const char *op = NULL; crm_data_t *diff = NULL; crm_data_t *aborted = NULL; const char *set_name = NULL; int diff_add_updates = 0; int diff_add_epoch = 0; int diff_add_admin_epoch = 0; int diff_del_updates = 0; int diff_del_epoch = 0; int diff_del_admin_epoch = 0; if(msg == NULL) { crm_err("NULL update"); return; } ha_msg_value_int(msg, F_CIB_RC, &rc); op = cl_get_string(msg, F_CIB_OPERATION); if(rc < cib_ok) { crm_debug_2("Ignoring failed %s operation: %s", op, cib_error2string(rc)); return; } diff = get_message_xml(msg, F_CIB_UPDATE_RESULT); cib_diff_version_details( diff, &diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates, &diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates); crm_info("Processing diff (%s): %d.%d.%d -> %d.%d.%d", op, diff_del_admin_epoch,diff_del_epoch,diff_del_updates, diff_add_admin_epoch,diff_add_epoch,diff_add_updates); log_cib_diff(LOG_DEBUG_2, diff, op); set_name = "diff-added"; if(diff != NULL && aborted == NULL) { crm_data_t *section = NULL; crm_data_t *change_set = find_xml_node(diff, set_name, FALSE); change_set = find_xml_node(change_set, XML_TAG_CIB, FALSE); if(change_set != NULL) { crm_debug_2("Checking status changes"); section=get_object_root(XML_CIB_TAG_STATUS,change_set); } if(section != NULL) { extract_event(section); } crm_debug_2("Checking change set: %s", set_name); aborted = need_abort(change_set); } set_name = "diff-removed"; if(diff != NULL && aborted == NULL) { crm_data_t *change_set = find_xml_node(diff, set_name, FALSE); change_set = find_xml_node(change_set, XML_TAG_CIB, FALSE); crm_debug_2("Checking change set: %s", set_name); aborted = need_abort(change_set); } if(aborted != NULL) { abort_transition( INFINITY, tg_restart, "Non-status change", NULL); } free_xml(diff); return; } gboolean process_te_message(HA_Message *msg, crm_data_t *xml_data, IPC_Channel *sender) { crm_data_t *xml_obj = NULL; const char *from = cl_get_string(msg, F_ORIG); const char *sys_to = cl_get_string(msg, F_CRM_SYS_TO); const char *sys_from = cl_get_string(msg, F_CRM_SYS_FROM); const char *ref = cl_get_string(msg, XML_ATTR_REFERENCE); const char *op = cl_get_string(msg, F_CRM_TASK); const char *type = cl_get_string(msg, F_CRM_MSG_TYPE); crm_debug_2("Processing %s (%s) message", op, ref); crm_log_message(LOG_DEBUG_3, msg); if(op == NULL){ /* error */ } else if(strcmp(op, CRM_OP_HELLO) == 0) { /* ignore */ } else if(sys_to == NULL || strcmp(sys_to, CRM_SYSTEM_TENGINE) != 0) { crm_debug_2("Bad sys-to %s", crm_str(sys_to)); return FALSE; } else if(safe_str_eq(op, CRM_OP_INVOKE_LRM) && safe_str_eq(sys_from, CRM_SYSTEM_LRMD) /* && safe_str_eq(type, XML_ATTR_RESPONSE) */ ){ #if CRM_DEPRECATED_SINCE_2_0_4 if(safe_str_eq(crm_element_name(xml_data), XML_TAG_CIB)) { xml_obj = xml_data; } else { xml_obj = find_xml_node(xml_data, XML_TAG_CIB, TRUE); } #else xml_obj = xml_data; - CRM_DEV_ASSERT(safe_str_eq(crm_element_name(xml_obj), XML_TAG_CIB)); + CRM_CHECK(xml_obj != NULL, + crm_log_message_adv(LOG_ERR, "Invalid (N)ACK", msg); + return FALSE); #endif - CRM_DEV_ASSERT(xml_obj != NULL); - if(xml_obj != NULL) { - xml_obj = get_object_root(XML_CIB_TAG_STATUS, xml_obj); - CRM_DEV_ASSERT(xml_obj != NULL); - } - if(xml_obj != NULL) { - crm_log_message_adv(LOG_DEBUG_2, "Processing NACK Reply", msg); - crm_debug("Processing NACK from %s", from); - extract_event(xml_obj); - } else { - crm_log_message_adv(LOG_ERR, "Invalid NACK Reply", msg); - } - + CRM_CHECK(xml_obj != NULL, + crm_log_message_adv(LOG_ERR, "Invalid (N)ACK", msg); + return FALSE); + xml_obj = get_object_root(XML_CIB_TAG_STATUS, xml_obj); + + CRM_CHECK(xml_obj != NULL, + crm_log_message_adv(LOG_ERR, "Invalid (N)ACK", msg); + return FALSE); + + crm_log_message_adv(LOG_DEBUG_2, "Processing (N)ACK", msg); + crm_debug("Processing (N)ACK from %s", from); + extract_event(xml_obj); } else if(safe_str_eq(type, XML_ATTR_RESPONSE)) { crm_err("Message was a response not a request. Discarding"); return TRUE; } else if(strcmp(op, CRM_OP_TRANSITION) == 0) { if(transition_graph->complete == FALSE) { crm_info("Another transition is already active"); abort_transition( INFINITY,tg_restart,"Transition Active",NULL); } else { destroy_graph(transition_graph); transition_graph = unpack_graph(xml_data); start_global_timer(transition_timer, transition_graph->transition_timeout); trigger_graph(); print_graph(LOG_DEBUG, transition_graph); } } else if(strcmp(op, CRM_OP_TE_HALT) == 0) { abort_transition(INFINITY, tg_stop, "Peer Halt", NULL); } else if(strcmp(op, CRM_OP_TEABORT) == 0) { abort_transition(INFINITY, tg_restart, "Peer Cancelled", NULL); } else { crm_err("Unknown command: %s::%s from %s", type, op, sys_from); } crm_debug_3("finished processing message"); return TRUE; } void tengine_stonith_callback(stonith_ops_t * op) { const char *allow_fail = NULL; int stonith_id = -1; crm_action_t *stonith_action = NULL; char *op_key = NULL; char *call_id = NULL; if(op == NULL) { crm_err("Called with a NULL op!"); return; } crm_info("call=%d, optype=%d, node_name=%s, result=%d, node_list=%s, action=%s", op->call_id, op->optype, op->node_name, op->op_result, (char *)op->node_list, op->private_data); /* this will mark the event complete if a match is found */ - CRM_DEV_ASSERT(op->private_data != NULL); + CRM_CHECK(op->private_data != NULL, return); /* filter out old STONITH actions */ decodeNVpair(op->private_data, ';', &call_id, &op_key); if(op_key != NULL) { char *key = generate_transition_key( transition_graph->id, te_uuid); gboolean key_matched = safe_str_eq(key, op_key); crm_free(key); if(key_matched == FALSE) { crm_info("Ignoring old STONITH op: %s", op->private_data); return; } } #if 1 stonith_id = crm_parse_int(call_id, "-1"); if(stonith_id < 0) { crm_err("Stonith action not matched: %s (%s)", call_id, op->private_data); return; } #endif stonith_action = match_down_event( stonith_id, op->node_uuid, CRM_OP_FENCE); if(stonith_action == NULL) { crm_err("Stonith action not matched"); return; } switch(op->op_result) { case STONITH_SUCCEEDED: send_stonith_update(op); break; case STONITH_CANNOT: case STONITH_TIMEOUT: case STONITH_GENERIC: stonith_action->failed = TRUE; allow_fail = g_hash_table_lookup( stonith_action->params, XML_ATTR_TE_ALLOWFAIL); if(FALSE == crm_is_true(allow_fail)) { crm_err("Stonith of %s failed (%d)..." " aborting transition.", op->node_name, op->op_result); abort_transition(INFINITY, tg_restart, "Stonith failed", NULL); } break; default: crm_err("Unsupported action result: %d", op->op_result); abort_transition(INFINITY, tg_restart, "Unsupport Stonith result", NULL); } update_graph(transition_graph, stonith_action); trigger_graph(); return; } void tengine_stonith_connection_destroy(gpointer user_data) { #if 0 crm_err("Fencing daemon has left us: Shutting down...NOW"); /* shutdown properly later */ - CRM_DEV_ASSERT(FALSE/* fencing daemon died */); + CRM_CHECK(FALSE/* fencing daemon died */); #else crm_err("Fencing daemon has left us"); #endif return; } gboolean tengine_stonith_dispatch(IPC_Channel *sender, void *user_data) { int lpc = 0; while(stonithd_op_result_ready()) { if (sender->ch_status == IPC_DISCONNECT) { /* The message which was pending for us is that * the IPC status is now IPC_DISCONNECT */ break; } if(ST_FAIL == stonithd_receive_ops_result(FALSE)) { crm_err("stonithd_receive_ops_result() failed"); } else { lpc++; } } crm_debug_2("Processed %d messages", lpc); if (sender->ch_status == IPC_DISCONNECT) { return FALSE; } return TRUE; } void cib_fencing_updated(const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data) { trigger_graph(); if(rc < cib_ok) { crm_err("CIB update failed: %s", cib_error2string(rc)); crm_log_xml_warn(msg, "[Failed Update]"); } } void cib_action_updated(const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data) { crm_action_t *action = user_data; const char *task_uuid = crm_element_value( action->xml, XML_LRM_ATTR_TASK_KEY); trigger_graph(); - CRM_DEV_ASSERT(rc == cib_ok); if(rc < cib_ok) { crm_err("Update for action %d (%s) FAILED: %s", action->id, task_uuid, cib_error2string(rc)); } } gboolean action_timer_callback(gpointer data) { crm_action_timer_t *timer = NULL; if(data == NULL) { crm_err("Timer popped with no data"); return FALSE; } timer = (crm_action_timer_t*)data; stop_te_timer(timer); crm_warn("Timer popped (abort_level=%d, complete=%s)", transition_graph->abort_priority, transition_graph->complete?"true":"false"); - CRM_DEV_ASSERT(timer->action != NULL); + CRM_CHECK(timer->action != NULL, return FALSE); if(transition_graph->complete) { crm_err("Ignoring timeout while not in transition"); } else if(timer->reason == timeout_action_warn) { print_graph_action( LOG_WARNING,"Action missed its timeout", timer->action); } else { /* fail the action */ cib_action_update(timer->action, LRM_OP_TIMEOUT); } return FALSE; } static int unconfirmed_actions(gboolean send_updates) { int unconfirmed = 0; crm_debug_2("Unconfirmed actions..."); slist_iter( synapse, synapse_t, transition_graph->synapses, lpc, /* lookup event */ slist_iter( action, crm_action_t, synapse->actions, lpc2, if(action->executed == FALSE) { continue; } else if(action->confirmed) { continue; } unconfirmed++; crm_debug("Action %d: unconfirmed",action->id); if(action->type == action_type_rsc && send_updates) { cib_action_update(action, LRM_OP_PENDING); } ); ); if(unconfirmed > 0) { crm_info("Waiting on %d unconfirmed actions", unconfirmed); } return unconfirmed; } gboolean global_timer_callback(gpointer data) { crm_action_timer_t *timer = NULL; if(data == NULL) { crm_err("Timer popped with no data"); return FALSE; } timer = (crm_action_timer_t*)data; stop_te_timer(timer); crm_warn("Timer popped (abort_level=%d, complete=%s)", transition_graph->abort_priority, transition_graph->complete?"true":"false"); - CRM_DEV_ASSERT(timer->action == NULL); + CRM_CHECK(timer->action == NULL, return FALSE); if(transition_graph->complete) { crm_err("Ignoring timeout while not in transition"); } else if(timer->reason == timeout_abort) { int unconfirmed = unconfirmed_actions(FALSE); crm_warn("Transition abort timeout reached..." " marking transition complete."); transition_graph->complete = TRUE; abort_transition(INFINITY, tg_restart, "Global Timeout", NULL); if(unconfirmed != 0) { crm_warn("Writing %d unconfirmed actions to the CIB", unconfirmed); unconfirmed_actions(TRUE); } } return FALSE; } gboolean te_graph_trigger(gpointer user_data) { int timeout = 0; - int pending_updates = 0; enum transition_status graph_rc = -1; if(transition_graph->complete) { notify_crmd(transition_graph); return TRUE; } graph_rc = run_graph(transition_graph); timeout = transition_graph->transition_timeout; print_graph(LOG_DEBUG_2, transition_graph); if(graph_rc == transition_active) { crm_debug_3("Transition not yet complete"); stop_te_timer(transition_timer); start_global_timer(transition_timer, timeout); return TRUE; } else if(graph_rc == transition_pending) { timeout = transition_timer->timeout; crm_debug_3("Transition not yet complete - no actions fired"); return TRUE; } - - pending_updates = num_cib_op_callbacks(); - CRM_DEV_ASSERT(pending_updates == 0); - if(graph_rc != transition_complete) { crm_err("Transition failed: %s", transition_status(graph_rc)); print_graph(LOG_WARNING, transition_graph); } notify_crmd(transition_graph); return TRUE; } diff --git a/crm/tengine/events.c b/crm/tengine/events.c index 30e3db7337..60012fc80c 100644 --- a/crm/tengine/events.c +++ b/crm/tengine/events.c @@ -1,458 +1,458 @@ -/* $Id: events.c,v 1.4 2006/02/16 18:20:33 andrew Exp $ */ +/* $Id: events.c,v 1.5 2006/03/18 17:23:48 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 crm_data_t *need_abort(crm_data_t *update); void process_graph_event(crm_data_t *event, const char *event_node); int match_graph_event( crm_action_t *action, crm_data_t *event, const char *event_node); crm_data_t * need_abort(crm_data_t *update) { crm_data_t *section_xml = NULL; const char *section = NULL; if(update == NULL) { return NULL; } section = XML_CIB_TAG_NODES; section_xml = get_object_root(section, update); xml_child_iter(section_xml, child, return section_xml; ); section = XML_CIB_TAG_RESOURCES; section_xml = get_object_root(section, update); xml_child_iter(section_xml, child, return section_xml; ); section = XML_CIB_TAG_CONSTRAINTS; section_xml = get_object_root(section, update); xml_child_iter(section_xml, child, return section_xml; ); section = XML_CIB_TAG_CRMCONFIG; section_xml = get_object_root(section, update); xml_child_iter(section_xml, child, return section_xml; ); return NULL; } gboolean extract_event(crm_data_t *msg) { int shutdown = 0; const char *event_node = NULL; /* [cib fragment] ... */ crm_debug_4("Extracting event from %s", crm_element_name(msg)); xml_child_iter_filter( msg, node_state, XML_CIB_TAG_STATE, crm_data_t *attrs = NULL; crm_data_t *resources = NULL; const char *ccm_state = crm_element_value( node_state, XML_CIB_ATTR_INCCM); const char *crmd_state = crm_element_value( node_state, XML_CIB_ATTR_CRMDSTATE); /* Transient node attribute changes... */ event_node = crm_element_value(node_state, XML_ATTR_ID); crm_debug("Processing state update from %s", event_node); crm_log_xml_debug_3(node_state,"Processing"); attrs = find_xml_node( node_state, XML_TAG_TRANSIENT_NODEATTRS, FALSE); if(attrs != NULL) { crm_info("Aborting on "XML_TAG_TRANSIENT_NODEATTRS" changes"); abort_transition(INFINITY, tg_restart, XML_TAG_TRANSIENT_NODEATTRS, attrs); } resources = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE); resources = find_xml_node( resources, XML_LRM_TAG_RESOURCES, FALSE); /* LRM resource update... */ xml_child_iter( resources, rsc, xml_child_iter( rsc, rsc_op, crm_log_xml_debug_3( rsc_op, "Processing resource update"); process_graph_event(rsc_op, event_node); ); ); /* * node state update... possibly from a shutdown we requested */ if(safe_str_eq(ccm_state, XML_BOOLEAN_FALSE) || safe_str_eq(crmd_state, CRMD_JOINSTATE_DOWN)) { crm_action_t *shutdown = NULL; crm_debug_3("A shutdown we requested?"); shutdown = match_down_event(0, event_node, NULL); if(shutdown != NULL) { update_graph(transition_graph, shutdown); trigger_graph(); } else { crm_info("Stonith/shutdown event not matched"); abort_transition(INFINITY, tg_restart, "Node failure", node_state); } } shutdown = 0; ha_msg_value_int(node_state, XML_CIB_ATTR_SHUTDOWN, &shutdown); if(shutdown != 0) { crm_info("Aborting on "XML_CIB_ATTR_SHUTDOWN" attribute"); abort_transition(INFINITY, tg_restart, "Shutdown request", node_state); } ); return TRUE; } /* * returns the ID of the action if a match is found * returns -1 if a match was not found * returns -2 if a match was found but the action failed (and was * not allowed to) */ int match_graph_event( crm_action_t *action, crm_data_t *event, const char *event_node) { int target_rc = 0; const char *target_rc_s = NULL; const char *allow_fail = NULL; const char *this_action = NULL; const char *this_node = NULL; const char *this_uname = NULL; const char *magic = NULL; const char *this_event; char *update_te_uuid = NULL; const char *update_event; int op_status_i = -3; int op_rc_i = -3; int transition_i = -1; - CRM_DEV_ASSERT(event != NULL); + CRM_CHECK(event != NULL, return -1); crm_debug_3("Processing \"%s\" change", crm_element_name(event)); update_event = crm_element_value(event, XML_ATTR_ID); magic = crm_element_value(event, XML_ATTR_TRANSITION_MAGIC); - CRM_DEV_ASSERT(magic != NULL); + CRM_CHECK(magic != NULL, return -2); this_action = crm_element_value(action->xml, XML_LRM_ATTR_TASK); this_uname = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); this_event = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY); this_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID); - CRM_DEV_ASSERT(this_event != NULL); + CRM_CHECK(this_event != NULL, return -2); if(safe_str_neq(this_event, update_event)) { crm_debug_2("Action %d : Event mismatch %s vs. %s", action->id, this_event, update_event); return -1; } else if(safe_str_neq(this_node, event_node)) { crm_debug_2("Action %d : Node mismatch %s (%s) vs. %s", action->id, this_node, this_uname, event_node); return -1; } crm_debug("Matched action (%d) %s", action->id, this_event); - CRM_DEV_ASSERT(decode_transition_magic( + CRM_CHECK(decode_transition_magic( magic, &update_te_uuid, - &transition_i, &op_status_i, &op_rc_i)); + &transition_i, &op_status_i, &op_rc_i), return -2); if(transition_i == -1) { /* we never expect these - recompute */ crm_err("Detected an action initiated outside of a transition"); crm_log_message(LOG_ERR, event); return -2; } else if(safe_str_neq(update_te_uuid, te_uuid)) { crm_info("Detected an action from a different transitioner:" " %s vs. %s", update_te_uuid, te_uuid); crm_log_message(LOG_INFO, event); return -3; } else if(transition_graph->id != transition_i) { crm_warn("Detected an action from a different transition:" " %d vs. %d", transition_i, transition_graph->id); crm_log_message(LOG_INFO, event); return -4; } /* stop this event's timer if it had one */ stop_te_timer(action->timer); action->confirmed = TRUE; target_rc_s = g_hash_table_lookup(action->params,XML_ATTR_TE_TARGET_RC); if(target_rc_s != NULL) { target_rc = crm_parse_int(target_rc_s, NULL); if(target_rc == op_rc_i) { crm_debug_2("Target rc: == %d", op_rc_i); if(op_status_i != LRM_OP_DONE) { crm_debug("Re-mapping op status to" " LRM_OP_DONE for %s", update_event); op_status_i = LRM_OP_DONE; } } else { crm_debug_2("Target rc: != %d", op_rc_i); if(op_status_i != LRM_OP_ERROR) { crm_info("Re-mapping op status to" " LRM_OP_ERROR for %s", update_event); op_status_i = LRM_OP_ERROR; } } } /* Process OP status */ switch(op_status_i) { case -3: crm_err("Action returned the same as last time..." " whatever that was!"); crm_log_message(LOG_ERR, event); break; case LRM_OP_PENDING: crm_debug("Ignoring pending operation"); return -5; break; case LRM_OP_DONE: break; case LRM_OP_ERROR: case LRM_OP_TIMEOUT: case LRM_OP_NOTSUPPORTED: action->failed = TRUE; crm_warn("Action %s on %s failed (rc: %d vs. %d): %s", update_event, event_node, target_rc, op_rc_i, op_status2text(op_status_i)); break; case LRM_OP_CANCELLED: /* do nothing?? */ crm_err("Dont know what to do for cancelled ops yet"); break; default: action->failed = TRUE; crm_err("Unsupported action result: %d", op_status_i); } update_graph(transition_graph, action); trigger_graph(); if(action->failed) { allow_fail = g_hash_table_lookup( action->params, XML_ATTR_TE_ALLOWFAIL); if(crm_is_true(allow_fail)) { action->failed = FALSE; } } if(action->failed) { abort_transition(action->synapse->priority, tg_restart, "Event failed", event); } else if(transition_graph->complete) { abort_transition(INFINITY, tg_restart,"No active graph", event); } te_log_action(LOG_INFO, "Action %s (%d) confirmed", this_event, action->id); return action->id; } crm_action_t * match_down_event(int id, const char *target, const char *filter) { const char *this_action = NULL; const char *this_node = NULL; crm_action_t *match = NULL; slist_iter( synapse, synapse_t, transition_graph->synapses, lpc, /* lookup event */ slist_iter( action, crm_action_t, synapse->actions, lpc2, if(id > 0 && action->id == id) { match = action; break; } this_action = crm_element_value( action->xml, XML_LRM_ATTR_TASK); if(action->type != action_type_crm) { continue; } else if(safe_str_eq(this_action, CRM_OP_LRM_REFRESH)){ continue; } else if(filter != NULL && safe_str_neq(this_action, filter)) { continue; } this_node = crm_element_value( action->xml, XML_LRM_ATTR_TARGET_UUID); if(this_node == NULL) { crm_log_xml_err(action->xml, "No node uuid"); } if(safe_str_neq(this_node, target)) { crm_debug("Action %d : Node mismatch: %s", action->id, this_node); continue; } match = action; break; ); if(match != NULL) { /* stop this event's timer if it had one */ break; } ); if(match != NULL) { /* stop this event's timer if it had one */ crm_debug("Match found for action %d: %s on %s", id, crm_element_value(match->xml, XML_LRM_ATTR_TASK_KEY), target); stop_te_timer(match->timer); match->confirmed = TRUE; } else if(id > 0) { crm_err("No match for action %d", id); } else { crm_warn("No match for shutdown action on %s", target); } return match; } void process_graph_event(crm_data_t *event, const char *event_node) { int rc = -1; int op_status_i = 0; const char *magic = NULL; const char *rsc_id = NULL; const char *op_status = NULL; CRM_ASSERT(event != NULL); rsc_id = crm_element_value(event, XML_ATTR_ID); op_status = crm_element_value(event, XML_LRM_ATTR_OPSTATUS); magic = crm_element_value(event, XML_ATTR_TRANSITION_MAGIC); if(op_status != NULL) { op_status_i = crm_parse_int(op_status, NULL); if(op_status_i == LRM_OP_PENDING) { /* just information that the action was sent */ crm_debug_2("Ignoring TE initiated updates"); return; } } if(magic == NULL) { crm_log_xml_debug_2(event, "Skipping \"non-change\""); return; } else { crm_debug_2("Processing CIB update: %s on %s: %s", rsc_id, event_node, magic); } slist_iter( synapse, synapse_t, transition_graph->synapses, lpc, /* lookup event */ slist_iter( action, crm_action_t, synapse->actions, lpc2, rc = match_graph_event(action, event, event_node); if(rc >= 0) { crm_log_xml_debug_2(event, "match:found"); } else if(rc == -5) { crm_log_xml_debug_2(event, "match:pending"); } else if(rc != -1) { crm_warn("Search terminated: %d", rc); abort_transition(INFINITY, tg_restart, "Unexpected event", event); } if(rc != -1) { return; } ); ); /* unexpected event, trigger a pe-recompute */ /* possibly do this only for certain types of actions */ crm_warn("Event not found."); abort_transition(INFINITY, tg_restart, "Unexpected event", event); return; } diff --git a/crm/tengine/fsa.c b/crm/tengine/fsa.c index 7f2e998768..9941c94988 100644 --- a/crm/tengine/fsa.c +++ b/crm/tengine/fsa.c @@ -1,89 +1,89 @@ -/* $Id: fsa.c,v 1.2 2005/06/14 11:38:26 davidlee Exp $ */ +/* $Id: fsa.c,v 1.3 2006/03/18 17:23:48 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 long long fsa_actions = a_nothing; enum te_fsa_state_t s_te_fsa(void) { while(g_list_length(input_queue)) { te_input_t *fsa_input = get_input();; crm_debug("Processing input %d", fsa_input->id); new_actions = te_action_matrix[fsa_input->input][te_fsa_state]; te_fsa_state = te_state_matrix[fsa_input->input][te_fsa_state]; fsa_actions |= new_actions; s_crmd_fsa_actions(fsa_input); } } void s_crmd_fsa_actions(te_input_t *fsa_input) { while(fsa_action != a_nothing) { IF_FSA_ACTION(A_EXIT_1, do_exit) else IF_FSA_ACTION(A_PROCESS_CIB_CALLBACK, do_cib_callback) else IF_FSA_ACTION(A_PROCESS_CIB_NOTIFY, do_cib_notify) else IF_FSA_ACTION(A_PROCESS_DC_COMMAND, do_dc_command) else IF_FSA_ACTION(A_DC_NOTIFY, do_notify_dc) } } /* A command from the DC */ void do_dc_command(enum te_fsa_state_t fsa_state, te_input_t *fsa_input) { struct te_data_command_s *data = fsa_data->data; - CRM_DEV_ASSERT(fsa_input->ops->type() == te_data_command); + CRM_CHECK(fsa_input->ops->type() == te_data_command); process_te_message(data->msg, data->xml); } /* A CIB update was confirmed */ void do_cib_callback(enum te_fsa_state_t fsa_state, te_input_t *fsa_input) { struct te_data_cib_s *data = fsa_data->data; - CRM_DEV_ASSERT(fsa_input->ops->type() == te_data_cib); + CRM_CHECK(fsa_input->ops->type() == te_data_cib); cib_action_updated(data->msg, data->call_id, data->rc, data->output, data->user_data); } /* Notification of an external CIB update */ void do_cib_notify(enum te_fsa_state_t fsa_state, te_input_t *fsa_input) { struct te_data_command_s *data = fsa_data->data; - CRM_DEV_ASSERT(fsa_input->ops->type() == te_data_command); + CRM_CHECK(fsa_input->ops->type() == te_data_command); te_update_confirm(NULL, data->msg); } void do_notify_dc(enum te_fsa_state_t fsa_state, te_input_t *fsa_input) { struct te_data_complete_s *data = fsa_data->data; - CRM_DEV_ASSERT(fsa_input->ops->type() == te_data_complete); + CRM_CHECK(fsa_input->ops->type() == te_data_complete); send_complete(data->text, data->msg, data->reason, data->input); } diff --git a/crm/tengine/fsa_data.c b/crm/tengine/fsa_data.c index 2abcf1b6c3..74308b32c1 100644 --- a/crm/tengine/fsa_data.c +++ b/crm/tengine/fsa_data.c @@ -1,330 +1,330 @@ -/* $Id: fsa_data.c,v 1.3 2005/06/14 11:38:26 davidlee Exp $ */ +/* $Id: fsa_data.c,v 1.4 2006/03/18 17:23:48 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 extern void te_input_free(te_input_t *fsa_data); extern te_input_t* te_input_copy(te_input_t *fsa_data); extern te_input_t* te_input_new(enum te_data_type type, void *data); extern te_input_t *new_input_command(HA_Message *msg, crm_data_t *xml); extern te_input_t *new_input_complete(const char *text, crm_data_t *xml, te_reason_t reason, te_fsa_input_t input); extern te_input_t *new_input_cib(HA_Message *msg, crm_data_t *xml, int call_id, int rc, void *user_data); extern te_input_t *new_input_null(void); const char* te_data_null_type(void); const char* te_data_null_name(void); void te_data_null_free(te_input_t *fsa_data); void te_data_null_copy(te_input_t *a_copy, te_input_t *fsa_data); const char* te_data_command_type(void); const char* te_data_command_name(void); void te_data_command_free(te_input_t *fsa_data); void te_data_command_copy(te_input_t *a_copy, te_input_t *fsa_data); const char* te_data_cib_type(void); const char* te_data_cib_name(void); void te_data_cib_free(te_input_t *fsa_data); void te_data_cib_copy(te_input_t *a_copy, te_input_t *fsa_data); const char* te_data_complete_type(void); const char* te_data_complete_name(void); void te_data_complete_free(te_input_t *fsa_data); void te_data_complete_copy(te_input_t *a_copy, te_input_t *fsa_data); GListPtr input_queue = NULL; te_data_op_t te_ops_null = { te_data_null_type, te_data_null_name, te_data_null_free, te_data_null_copy }; te_data_op_t te_ops_cib = { te_data_cib_type, te_data_cib_name, te_data_cib_free, te_data_cib_copy }; te_data_op_t te_ops_complete = { te_data_complete_type, te_data_complete_name, te_data_complete_free, te_data_complete_copy }; te_data_op_t te_ops_command = { te_data_command_type, te_data_command_name, te_data_command_free, te_data_command_copy }; void te_input_free(te_input_t *fsa_data) { if(fsa_data == NULL) { return; } fsa_data->ops->free(fsa_data); crm_free(fsa_data); } te_input_t* te_input_copy(te_input_t *fsa_data) { te_input_t *a_copy = NULL; - CRM_DEV_ASSERT(fsa_data != NULL); if(crm_assert_failed) {return NULL;} + CRM_CHECK(fsa_data != NULL); if(crm_assert_failed) {return NULL;} crm_malloc0(a_copy, sizeof(te_input_t)); *a_copy = *fsa_data; a_copy->data = NULL; a_copy->ops->copy(fsa_data); } te_input_t* te_input_new( te_fsa_input_t input, enum te_data_type type, void *data) { static int input_id = 0; te_input_t *a_copy = NULL; crm_malloc0(a_copy, sizeof(te_input_t)); a_copy->id = input_id++; a_copy->origin = origin; a_copy->input = input; a_copy->data = data; switch(type) { case te_data_cib: a_copy->ops = &te_ops_cib; break; case te_data_complete: a_copy->ops = &te_ops_complete; break; case te_data_command: a_copy->ops = &te_ops_command; break; case te_data_null: a_copy->ops = &te_ops_null; break; } } const char* te_data_null_type(void) { return te_data_null; } const char* te_data_null_name(void) { return "Null"; } void te_data_null_free(te_input_t *fsa_data) { } void te_data_null_copy(te_input_t *a_copy, te_input_t *fsa_data) { a_copy->data = NULL; } const char* te_data_command_type(void) { return te_data_command; } const char* te_data_command_name(void) { return "DC Command"; } void te_data_command_free(te_input_t *fsa_data) { struct te_data_command_s *data = fsa_data->data; - CRM_DEV_ASSERT(fsa_data->ops->type() == te_data_command); + CRM_CHECK(fsa_data->ops->type() == te_data_command); ha_msg_del(data->msg); free_xml(data->xml); crm_free(data); } void te_data_command_copy(te_input_t *a_copy, te_input_t *fsa_data) { struct te_data_command_s *data = fsa_data->data; struct te_data_command_s *copy_data = NULL; - CRM_DEV_ASSERT(fsa_data->ops->type() == te_data_command); + CRM_CHECK(fsa_data->ops->type() == te_data_command); crm_malloc0(a_copy->data, sizeof(struct te_data_command_s)); copy_data = a_copy->data; copy_data->msg = ha_msg_copy(data->msg); copy_data->xml = copy_xml(data->xml); } const char* te_data_cib_type(void) { return te_data_cib; } const char* te_data_cib_name(void) { return "CIB Callback"; } void te_data_cib_free(te_input_t *fsa_data) { struct te_data_cib_s *data = fsa_data->data; - CRM_DEV_ASSERT(fsa_data->ops->type() == te_data_cib); + CRM_CHECK(fsa_data->ops->type() == te_data_cib); ha_msg_del(data->msg); free_xml(data->xml); crm_free(data); } void te_data_cib_copy(te_input_t *a_copy, te_input_t *fsa_data) { struct te_data_cib_s *data = fsa_data->data; struct te_data_cib_s *copy_data = NULL; - CRM_DEV_ASSERT(fsa_data->ops->type() == te_data_cib); + CRM_CHECK(fsa_data->ops->type() == te_data_cib); crm_malloc0(a_copy->data, sizeof(struct te_data_cib_s)); copy_data = a_copy->data; *copy_data = *data; copy_data->msg = ha_msg_copy(data->msg); copy_data->xml = copy_xml(data->xml); } const char* te_data_complete_type(void) { return te_data_complete; } const char* te_data_complete_name(void) { return "Transition Complete"; } void te_data_complete_free(te_input_t *fsa_data) { struct te_data_complete_s *data = fsa_data->data; - CRM_DEV_ASSERT(fsa_data->ops->type() == te_data_complete); + CRM_CHECK(fsa_data->ops->type() == te_data_complete); ha_msg_del(data->msg); free_xml(data->xml); crm_free(data); } void te_data_complete_copy(te_input_t *a_copy, te_input_t *fsa_data) { struct te_data_complete_s *data = fsa_data->data; struct te_data_complete_s *copy_data = NULL; - CRM_DEV_ASSERT(fsa_data->ops->type() == te_data_complete); + CRM_CHECK(fsa_data->ops->type() == te_data_complete); crm_malloc0(a_copy->data, sizeof(struct te_data_complete_s)); copy_data = a_copy->data; *copy_data = *data; copy_data->xml = copy_xml(data->xml); } te_input_t * new_input_command(HA_Message *msg, crm_data_t *xml) { struct te_data_cib_s *copy_data = NULL; crm_malloc0(a_copy->data, sizeof(struct te_data_cib_s)); copy_data = a_copy->data; copy_data->xml = copy_xml(xml); copy_data->msg = ha_msg_copy(msg); return te_input_new(te_data_command, copy_data); } te_input_t * new_input_complete(const char *text, crm_data_t *xml, te_reason_t reason) { struct te_data_complete_s *copy_data = NULL; crm_malloc0(a_copy->data, sizeof(struct te_data_complete_s)); copy_data = a_copy->data; copy_data->text = text; copy_data->reason = reason; copy_data->xml = copy_xml(xml); return te_input_new(te_data_complete, copy_data); } te_input_t * new_input_cib(HA_Message *msg, crm_data_t *xml, int call_id, int rc, void *user_data) { struct te_data_cib_s *copy_data = NULL; crm_malloc0(a_copy->data, sizeof(struct te_data_cib_s)); copy_data = a_copy->data; copy_data->rc = rc; copy_data->call_id = call_id; copy_data->user_data = user_data; copy_data->msg = ha_msg_copy(msg); copy_data->xml = copy_xml(xml); return te_input_new(te_data_cib, copy_data); } te_input_t * new_input_null(const char *origin) { return te_input_new(te_data_null, NULL, origin); } void register_input(te_fsa_input_t input, te_input_t *input_data, gboolean prepend, const char *origin) { input_data->origin = origin; input_data->input = input; crm_debug("%s raised FSA input %d (%s)", origin, input_data->id, input_data->ops->name()); if(prepend) { crm_debug_2("Prepending input"); input_queue = g_list_prepend(input_queue, input_data); } else { input_queue = g_list_append(input_queue, input_data); } G_main_set_trigger(fsa_source); } void register_input_copy(te_fsa_input_t input, te_input_t *input_data, gboolean prepend, const char *origin) { te_input_t *a_copy = input_data->ops->copy(input); crm_debug("%s re-registering FSA input %d (%s/%s)", origin, input_data->id, input_data->ops->name(), input_data->origin); register_input(a_copy, prepend, origin); } te_input_t * get_input(void) { te_input_t* message = g_list_nth_data(input_queue, 0); input_queue = g_list_remove(input_queue, message); return message; } diff --git a/crm/tengine/utils.c b/crm/tengine/utils.c index 1f027c856c..a9d1cd0a0a 100644 --- a/crm/tengine/utils.c +++ b/crm/tengine/utils.c @@ -1,134 +1,140 @@ -/* $Id: utils.c,v 1.57 2006/02/27 09:55:57 andrew Exp $ */ +/* $Id: utils.c,v 1.58 2006/03/18 17:23:48 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 extern cib_t *te_cib_conn; const char * get_rsc_state(const char *task, op_status_t status) { if(safe_str_eq(CRMD_ACTION_START, task)) { if(status == LRM_OP_PENDING) { return CRMD_ACTION_START_PENDING; } else if(status == LRM_OP_DONE) { return CRMD_ACTION_STARTED; } else { return CRMD_ACTION_START_FAIL; } } else if(safe_str_eq(CRMD_ACTION_STOP, task)) { if(status == LRM_OP_PENDING) { return CRMD_ACTION_STOP_PENDING; } else if(status == LRM_OP_DONE) { return CRMD_ACTION_STOPPED; } else { return CRMD_ACTION_STOP_FAIL; } } else { if(safe_str_eq(CRMD_ACTION_MON, task)) { if(status == LRM_OP_PENDING) { return CRMD_ACTION_MON_PENDING; } else if(status == LRM_OP_DONE) { return CRMD_ACTION_MON_OK; } else { return CRMD_ACTION_MON_FAIL; } } else { const char *rsc_state = NULL; if(status == LRM_OP_PENDING) { rsc_state = CRMD_ACTION_GENERIC_PENDING; } else if(status == LRM_OP_DONE) { rsc_state = CRMD_ACTION_GENERIC_OK; } else { rsc_state = CRMD_ACTION_GENERIC_FAIL; } crm_warn("Using status \"%s\" for op \"%s\"..." " this is still in the experimental stage.", rsc_state, task); return rsc_state; } } } gboolean stop_te_timer(crm_action_timer_t *timer) { + const char *timer_desc = "action timer"; + if(timer == NULL) { return FALSE; } + if(timer->reason == timeout_abort) { + timer_desc = "global timer"; + } if(timer->source_id != 0) { + crm_debug("Stopping %s", timer_desc); Gmain_timeout_remove(timer->source_id); timer->source_id = 0; } else { return FALSE; } return TRUE; } void trigger_graph_processing(const char *fn, int line) { G_main_set_trigger(transition_trigger); crm_debug_2("%s:%d - Triggered graph processing", fn, line); } void abort_transition_graph( int abort_priority, enum transition_action abort_action, const char *abort_text, crm_data_t *reason, const char *fn, int line) { int log_level = LOG_DEBUG; if(abort_priority >= INFINITY) { log_level = LOG_INFO; } update_abort_priority( transition_graph, abort_priority, abort_action, abort_text); crm_log_maybe(log_level, "%s:%d - Triggered graph processing : %s", fn, line, abort_text); if(reason != NULL) { crm_log_xml(log_level, "Cause", reason); } if(transition_graph->complete) { notify_crmd(transition_graph); } else { G_main_set_trigger(transition_trigger); } } diff --git a/lib/crm/cib/cib_attrs.c b/lib/crm/cib/cib_attrs.c index 6c94d67d2d..f158ec2ba1 100644 --- a/lib/crm/cib/cib_attrs.c +++ b/lib/crm/cib/cib_attrs.c @@ -1,496 +1,499 @@ -/* $Id: cib_attrs.c,v 1.13 2006/02/03 08:29:22 andrew Exp $ */ +/* $Id: cib_attrs.c,v 1.14 2006/03/18 17:23:48 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 enum cib_errors update_attr(cib_t *the_cib, int call_options, const char *section, const char *node_uuid, const char *set_name, const char *attr_id, const char *attr_name, const char *attr_value) { const char *tag = NULL; enum cib_errors rc = cib_ok; crm_data_t *xml_top = NULL; crm_data_t *xml_obj = NULL; crm_data_t *fragment = NULL; if(attr_id == NULL) { attr_id = attr_name; } if(attr_name == NULL) { attr_name = attr_id; } CRM_ASSERT(attr_id != NULL); CRM_ASSERT(attr_name != NULL); if(safe_str_eq(section, XML_CIB_TAG_CRMCONFIG)) { tag = NULL; } else if(safe_str_eq(section, XML_CIB_TAG_NODES)) { tag = XML_CIB_TAG_NODE; } else if(section != NULL && node_uuid != NULL) { xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_STATE); crm_xml_add(xml_obj, XML_ATTR_ID, node_uuid); if(xml_top == NULL) { xml_top = xml_obj; } tag = XML_TAG_TRANSIENT_NODEATTRS; } else if(section != NULL) { tag = XML_TAG_TRANSIENT_NODEATTRS; } else { return cib_NOSECTION; } crm_debug_2("Creating %s/%s", section, tag); if(tag != NULL) { xml_obj = create_xml_node(xml_obj, tag); crm_xml_add(xml_obj, XML_ATTR_ID, node_uuid); if(xml_top == NULL) { xml_top = xml_obj; } } if(set_name != NULL) { xml_obj = create_xml_node(xml_obj, XML_TAG_ATTR_SETS); if(xml_top == NULL) { xml_top = xml_obj; } crm_xml_add(xml_obj, XML_ATTR_ID, set_name); xml_obj = create_xml_node(xml_obj, XML_TAG_ATTRS); } xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_NVPAIR); if(xml_top == NULL) { xml_top = xml_obj; } crm_xml_add(xml_obj, XML_ATTR_ID, attr_id); crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name); crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, attr_value); crm_log_xml_debug_2(xml_top, "Update"); fragment = create_cib_fragment(xml_top, section); crm_log_xml_debug_3(fragment, "Update Fragment"); free_xml(xml_top); rc = the_cib->cmds->update( the_cib, section, fragment, NULL, call_options|cib_quorum_override); if(rc == cib_diff_resync) { /* this is an internal matter - the update succeeded */ rc = cib_ok; } if(rc < cib_ok) { crm_err("Error setting %s=%s (section=%s, set=%s): %s", attr_name, attr_value, section, crm_str(set_name), cib_error2string(rc)); } free_xml(fragment); return rc; } enum cib_errors read_attr(cib_t *the_cib, const char *section, const char *node_uuid, const char *set_name, const char *attr_id, const char *attr_name, char **attr_value) { const char *tag = NULL; enum cib_errors rc = cib_ok; crm_data_t *a_node = NULL; crm_data_t *xml_obj = NULL; crm_data_t *xml_next = NULL; crm_data_t *fragment = NULL; CRM_ASSERT(attr_value != NULL); *attr_value = NULL; crm_debug("Searching for attribute %s (section=%s, node=%s, set=%s)", attr_name, section, crm_str(node_uuid), crm_str(set_name)); rc = the_cib->cmds->query( the_cib, section, &fragment, cib_sync_call); if(rc != cib_ok) { crm_err("Query failed for attribute %s (section=%s, node=%s, set=%s): %s", attr_name, section, crm_str(set_name), crm_str(node_uuid), cib_error2string(rc)); return rc; } #if CRM_DEPRECATED_SINCE_2_0_4 if(safe_str_eq(crm_element_name(fragment), section)) { xml_obj = fragment; } else { a_node = find_xml_node(fragment, XML_TAG_CIB, TRUE); xml_obj = get_object_root(section, a_node); } #else xml_obj = fragment; - CRM_DEV_ASSERT(safe_str_eq(crm_element_name(xml_obj), XML_TAG_CIB)); + CRM_CHECK(safe_str_eq(crm_element_name(xml_obj), XML_TAG_CIB), + return cib_output_data); #endif CRM_ASSERT(xml_obj != NULL); crm_log_xml_debug_2(xml_obj, "Result section"); if(safe_str_eq(section, XML_CIB_TAG_CRMCONFIG)) { tag = NULL; } else if(safe_str_eq(section, XML_CIB_TAG_NODES)) { tag = XML_CIB_TAG_NODE; } else if(section != NULL && node_uuid != NULL) { xml_next = find_entity(xml_obj, XML_CIB_TAG_STATE, node_uuid); tag = XML_TAG_TRANSIENT_NODEATTRS; if(xml_next == NULL) { crm_debug("%s=%s not found in %s", XML_CIB_TAG_STATE, node_uuid, crm_element_name(xml_obj)); return cib_NOTEXISTS; } xml_obj = xml_next; } else if(section != NULL) { tag = XML_TAG_TRANSIENT_NODEATTRS; } else { return cib_NOSECTION; } if(tag != NULL) { xml_next = find_entity(xml_obj, tag, node_uuid); if(xml_next == NULL) { crm_debug("%s=%s not found in %s", tag, node_uuid, crm_element_name(xml_obj)); return cib_NOTEXISTS; } xml_obj = xml_next; } if(set_name != NULL) { xml_next = find_entity(xml_obj, XML_TAG_ATTR_SETS, set_name); if(xml_next == NULL) { crm_debug("%s=%s object not found in %s", XML_TAG_ATTR_SETS, set_name, crm_element_name(xml_obj)); return cib_NOTEXISTS; } xml_obj = xml_next; xml_next = find_xml_node(xml_obj, XML_TAG_ATTRS, TRUE); if(xml_next == NULL) { crm_debug("%s object not found in %s", XML_TAG_ATTRS, crm_element_name(xml_obj)); return cib_NOTEXISTS; } xml_obj = xml_next; } xml_next = NULL; xml_child_iter_filter( xml_obj, a_child, XML_CIB_TAG_NVPAIR, const char *name = crm_element_value( a_child, XML_NVPAIR_ATTR_NAME); if(attr_id != NULL && safe_str_neq(attr_id, ID(a_child))) { continue; } else if(attr_name != NULL && safe_str_neq(attr_name, name)) { continue; } xml_next = a_child; break; ); if(xml_next == NULL) { crm_debug("<%s id=%s name=%s/> not found in %s", XML_CIB_TAG_NVPAIR, attr_id, attr_name, crm_element_name(xml_obj)); return cib_NOTEXISTS; } xml_obj = xml_next; if(crm_element_value(xml_obj, XML_NVPAIR_ATTR_VALUE) != NULL) { *attr_value = crm_element_value_copy( xml_obj, XML_NVPAIR_ATTR_VALUE); } free_xml(fragment); return cib_ok; } enum cib_errors delete_attr(cib_t *the_cib, const char *section, const char *node_uuid, const char *set_name, const char *attr_id, const char *attr_name, const char *attr_value) { char *tmp = NULL; enum cib_errors rc = cib_ok; crm_data_t *xml_obj = NULL; rc = read_attr(the_cib, section, node_uuid, set_name, attr_id, attr_name, &tmp); if(rc != cib_ok) { return rc; } else if(attr_value != NULL && safe_str_neq(attr_value, tmp)) { crm_free(tmp); return cib_NOTEXISTS; } crm_free(tmp); xml_obj = create_xml_node(NULL, XML_CIB_TAG_NVPAIR); crm_xml_add(xml_obj, XML_ATTR_ID, attr_id); crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, attr_name); crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, attr_value); rc = the_cib->cmds->delete( the_cib, section, xml_obj, NULL, cib_sync_call|cib_quorum_override); free_xml(xml_obj); return rc; } enum cib_errors query_node_uuid(cib_t *the_cib, const char *uname, char **uuid) { enum cib_errors rc = cib_ok; crm_data_t *xml_obj = NULL; crm_data_t *fragment = NULL; const char *child_name = NULL; CRM_ASSERT(uname != NULL); CRM_ASSERT(uuid != NULL); rc = the_cib->cmds->query( the_cib, XML_CIB_TAG_NODES, &fragment, cib_sync_call); if(rc != cib_ok) { return rc; } #if CRM_DEPRECATED_SINCE_2_0_4 if(safe_str_eq(crm_element_name(fragment), XML_CIB_TAG_NODES)) { xml_obj = fragment; } else { xml_obj = find_xml_node(fragment, XML_TAG_CIB, TRUE); xml_obj = get_object_root(XML_CIB_TAG_NODES, xml_obj); } #else xml_obj = fragment; - CRM_DEV_ASSERT(safe_str_eq(crm_element_name(xml_obj), XML_TAG_CIB)); + CRM_CHECK(safe_str_eq(crm_element_name(xml_obj), XML_TAG_CIB), + return cib_output_data); #endif CRM_ASSERT(xml_obj != NULL); crm_log_xml_debug(xml_obj, "Result section"); rc = cib_NOTEXISTS; *uuid = NULL; xml_child_iter_filter( xml_obj, a_child, XML_CIB_TAG_NODE, child_name = crm_element_value(a_child, XML_ATTR_UNAME); if(safe_str_eq(uname, child_name)) { child_name = ID(a_child); if(child_name != NULL) { *uuid = crm_strdup(child_name); rc = cib_ok; } break; } ); free_xml(fragment); return rc; } enum cib_errors query_node_uname(cib_t *the_cib, const char *uuid, char **uname) { enum cib_errors rc = cib_ok; crm_data_t *xml_obj = NULL; crm_data_t *fragment = NULL; const char *child_name = NULL; CRM_ASSERT(uname != NULL); CRM_ASSERT(uuid != NULL); rc = the_cib->cmds->query( the_cib, XML_CIB_TAG_NODES, &fragment, cib_sync_call); if(rc != cib_ok) { return rc; } #if CRM_DEPRECATED_SINCE_2_0_4 if(safe_str_eq(crm_element_name(fragment), XML_CIB_TAG_NODES)) { xml_obj = fragment; } else { xml_obj = find_xml_node(fragment, XML_TAG_CIB, TRUE); xml_obj = get_object_root(XML_CIB_TAG_NODES, xml_obj); } #else xml_obj = fragment; - CRM_DEV_ASSERT(safe_str_eq(crm_element_name(xml_obj), XML_TAG_CIB)); + CRM_CHECK(safe_str_eq(crm_element_name(xml_obj), XML_TAG_CIB), + return cib_output_data); #endif CRM_ASSERT(xml_obj != NULL); crm_log_xml_debug_2(xml_obj, "Result section"); rc = cib_NOTEXISTS; *uname = NULL; xml_child_iter_filter( xml_obj, a_child, XML_CIB_TAG_NODE, child_name = ID(a_child); if(safe_str_eq(uuid, child_name)) { child_name = crm_element_value(a_child, XML_ATTR_UNAME); if(child_name != NULL) { *uname = crm_strdup(child_name); rc = cib_ok; } break; } ); free_xml(fragment); return rc; } #define standby_common char *attr_id = NULL; \ int str_length = 3; \ char *set_name = NULL; \ const char *attr_name = "standby"; \ const char *type = XML_CIB_TAG_NODES; \ \ - CRM_DEV_ASSERT(uuid != NULL); \ - CRM_DEV_ASSERT(standby_value != NULL); \ + CRM_CHECK(uuid != NULL, return cib_missing_data); \ + CRM_CHECK(standby_value != NULL, return cib_missing_data); \ str_length += strlen(attr_name); \ str_length += strlen(uuid); \ if(safe_str_eq(scope, "reboot") \ || safe_str_eq(scope, XML_CIB_TAG_STATUS)) { \ const char *extra = "transient"; \ type = XML_CIB_TAG_STATUS; \ str_length += strlen(extra); \ crm_malloc0(attr_id, str_length); \ sprintf(attr_id, "%s-%s-%s", extra, attr_name, uuid); \ \ } else { \ crm_malloc0(attr_id, str_length); \ sprintf(attr_id, "%s-%s", attr_name, uuid); \ } \ set_name = crm_strdup(attr_id); enum cib_errors query_standby(cib_t *the_cib, const char *uuid, const char *scope, char **standby_value) { enum cib_errors rc = cib_ok; if(scope != NULL) { standby_common; rc = read_attr(the_cib, type, uuid, set_name, attr_id, attr_name, standby_value); crm_free(attr_id); crm_free(set_name); } else { rc = query_standby( the_cib, uuid, XML_CIB_TAG_NODES, standby_value); if(rc == cib_NOTEXISTS) { crm_debug("No standby value found with " "lifetime=forever, checking lifetime=reboot"); rc = query_standby(the_cib, uuid, XML_CIB_TAG_STATUS, standby_value); } } return rc; } enum cib_errors set_standby(cib_t *the_cib, const char *uuid, const char *scope, const char *standby_value) { enum cib_errors rc = cib_ok; if(scope != NULL) { standby_common; rc = update_attr(the_cib, cib_sync_call, type, uuid, set_name, attr_id, attr_name, standby_value); crm_free(attr_id); crm_free(set_name); } else { rc = set_standby(the_cib, uuid, XML_CIB_TAG_NODES, standby_value); } return rc; } enum cib_errors delete_standby(cib_t *the_cib, const char *uuid, const char *scope, const char *standby_value) { enum cib_errors rc = cib_ok; if(scope != NULL) { standby_common; rc = delete_attr(the_cib, type, uuid, set_name, attr_id, attr_name, standby_value); crm_free(attr_id); crm_free(set_name); } else { rc = delete_standby( the_cib, uuid, XML_CIB_TAG_STATUS, standby_value); rc = delete_standby( the_cib, uuid, XML_CIB_TAG_NODES, standby_value); } return rc; } diff --git a/lib/crm/cib/cib_client.c b/lib/crm/cib/cib_client.c index 7f9bc2aa50..82b50dca02 100755 --- a/lib/crm/cib/cib_client.c +++ b/lib/crm/cib/cib_client.c @@ -1,1503 +1,1501 @@ /* * Copyright (c) 2004 International Business Machines * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser 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 library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 /* short term hack to reduce callback messages */ typedef struct cib_native_opaque_s { IPC_Channel *command_channel; IPC_Channel *callback_channel; GCHSource *callback_source; } cib_native_opaque_t; GHashTable *cib_op_callback_table = NULL; gboolean verify_cib_cmds(cib_t *cib); int cib_client_set_op_callback( cib_t *cib, void (*callback)(const struct ha_msg *msg, int call_id, int rc, crm_data_t *output)); int cib_client_noop(cib_t *cib, int call_options); int cib_client_ping(cib_t *cib, crm_data_t **output_data, int call_options); int cib_client_query(cib_t *cib, const char *section, crm_data_t **output_data, int call_options); int cib_client_query_from(cib_t *cib, const char *host, const char *section, crm_data_t **output_data, int call_options); int cib_client_sync(cib_t *cib, const char *section, int call_options); int cib_client_sync_from( cib_t *cib, const char *host, const char *section, int call_options); int cib_client_is_master(cib_t *cib); int cib_client_set_slave(cib_t *cib, int call_options); int cib_client_set_slave_all(cib_t *cib, int call_options); int cib_client_set_master(cib_t *cib, int call_options); int cib_client_bump_epoch(cib_t *cib, int call_options); int cib_client_create(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options); int cib_client_modify(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options); int cib_client_update(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options); int cib_client_replace(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options); int cib_client_delete(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options); int cib_client_delete_absolute( cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options); int cib_client_erase( cib_t *cib, crm_data_t **output_data, int call_options); int cib_client_quit(cib_t *cib, int call_options); int cib_client_add_notify_callback( cib_t *cib, const char *event, void (*callback)( const char *event, struct ha_msg *msg)); int cib_client_del_notify_callback( cib_t *cib, const char *event, void (*callback)( const char *event, struct ha_msg *msg)); gint ciblib_GCompareFunc(gconstpointer a, gconstpointer b); extern cib_t *cib_native_new(cib_t *cib); extern void cib_native_delete(cib_t *cib); static enum cib_variant configured_variant = cib_native; /* define of the api functions*/ cib_t* cib_new(void) { cib_t* new_cib = NULL; if(configured_variant != cib_native) { crm_err("Only the native CIB type is currently implemented"); return NULL; } if(cib_op_callback_table != NULL) { g_hash_table_destroy(cib_op_callback_table); cib_op_callback_table = NULL; } if(cib_op_callback_table == NULL) { cib_op_callback_table = g_hash_table_new_full( g_direct_hash, g_direct_equal, NULL, g_hash_destroy_str); } crm_malloc0(new_cib, sizeof(cib_t)); new_cib->call_id = 1; new_cib->type = cib_none; new_cib->state = cib_disconnected; new_cib->op_callback = NULL; new_cib->variant_opaque = NULL; new_cib->notify_list = NULL; /* the rest will get filled in by the variant constructor */ crm_malloc0(new_cib->cmds, sizeof(cib_api_operations_t)); new_cib->cmds->set_op_callback = cib_client_set_op_callback; new_cib->cmds->add_notify_callback = cib_client_add_notify_callback; new_cib->cmds->del_notify_callback = cib_client_del_notify_callback; new_cib->cmds->noop = cib_client_noop; new_cib->cmds->ping = cib_client_ping; new_cib->cmds->query = cib_client_query; new_cib->cmds->sync = cib_client_sync; new_cib->cmds->query_from = cib_client_query_from; new_cib->cmds->sync_from = cib_client_sync_from; new_cib->cmds->is_master = cib_client_is_master; new_cib->cmds->set_master = cib_client_set_master; new_cib->cmds->set_slave = cib_client_set_slave; new_cib->cmds->set_slave_all = cib_client_set_slave_all; new_cib->cmds->bump_epoch = cib_client_bump_epoch; new_cib->cmds->create = cib_client_create; new_cib->cmds->modify = cib_client_modify; new_cib->cmds->update = cib_client_update; new_cib->cmds->replace = cib_client_replace; new_cib->cmds->delete = cib_client_delete; new_cib->cmds->erase = cib_client_erase; new_cib->cmds->quit = cib_client_quit; new_cib->cmds->delete_absolute = cib_client_delete_absolute; cib_native_new(new_cib); if(verify_cib_cmds(new_cib) == FALSE) { return NULL; } return new_cib; } void cib_delete(cib_t *cib) { cib_native_delete(cib); g_hash_table_destroy(cib_op_callback_table); crm_free(cib->cmds); crm_free(cib); } int cib_client_set_op_callback( cib_t *cib, void (*callback)(const struct ha_msg *msg, int call_id, int rc, crm_data_t *output)) { if(callback == NULL) { crm_info("Un-Setting operation callback"); } else { crm_debug_3("Setting operation callback"); } cib->op_callback = callback; return cib_ok; } int cib_client_noop(cib_t *cib, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op( cib, CRM_OP_NOOP, NULL, NULL, NULL, NULL, call_options); } int cib_client_ping(cib_t *cib, crm_data_t **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op( cib, CRM_OP_PING, NULL,NULL,NULL, output_data, call_options); } int cib_client_query(cib_t *cib, const char *section, crm_data_t **output_data, int call_options) { return cib->cmds->query_from( cib, NULL, section, output_data, call_options); } int cib_client_query_from(cib_t *cib, const char *host, const char *section, crm_data_t **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op(cib, CIB_OP_QUERY, host, section, NULL, output_data, call_options); } int cib_client_is_master(cib_t *cib) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op( cib, CIB_OP_ISMASTER, NULL, NULL,NULL,NULL, cib_scope_local|cib_sync_call); } int cib_client_set_slave(cib_t *cib, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op( cib, CIB_OP_SLAVE, NULL,NULL,NULL,NULL, call_options); } int cib_client_set_slave_all(cib_t *cib, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op( cib, CIB_OP_SLAVEALL, NULL,NULL,NULL,NULL, call_options); } int cib_client_set_master(cib_t *cib, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } crm_debug_3("Adding cib_scope_local to options"); return cib->cmds->variant_op( cib, CIB_OP_MASTER, NULL,NULL,NULL,NULL, call_options|cib_scope_local); } int cib_client_bump_epoch(cib_t *cib, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op( cib, CIB_OP_BUMP, NULL, NULL, NULL, NULL, call_options); } int cib_client_sync(cib_t *cib, const char *section, int call_options) { return cib->cmds->sync_from(cib, NULL, section, call_options); } int cib_client_sync_from( cib_t *cib, const char *host, const char *section, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op( cib, CIB_OP_SYNC, host, section, NULL, NULL, call_options); } int cib_client_create(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op(cib, CIB_OP_CREATE, NULL, section, data, output_data, call_options); } int cib_client_modify(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op(cib, CIB_OP_MODIFY, NULL, section, data, output_data, call_options); } int cib_client_update(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op(cib, CIB_OP_UPDATE, NULL, section, data, output_data, call_options); } int cib_client_replace(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } else if(data == NULL) { return cib_missing_data; } return cib->cmds->variant_op(cib, CIB_OP_REPLACE, NULL, section, data, output_data, call_options); } int cib_client_delete(cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op(cib, CIB_OP_DELETE, NULL, section, data, output_data, call_options); } int cib_client_delete_absolute( cib_t *cib, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op(cib, CIB_OP_DELETE_ALT, NULL, section, data, output_data, call_options); } int cib_client_erase( cib_t *cib, crm_data_t **output_data, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op(cib, CIB_OP_ERASE, NULL, NULL, NULL, output_data, call_options); } int cib_client_quit(cib_t *cib, int call_options) { if(cib == NULL) { return cib_missing; } else if(cib->state == cib_disconnected) { return cib_not_connected; } else if(cib->cmds->variant_op == NULL) { return cib_variant; } return cib->cmds->variant_op( cib, CRM_OP_QUIT, NULL, NULL, NULL, NULL, call_options); } int cib_client_add_notify_callback( cib_t *cib, const char *event, void (*callback)( const char *event, struct ha_msg *msg)) { GList *list_item = NULL; cib_notify_client_t *new_client = NULL; crm_debug_2("Adding callback for %s events (%d)", event, g_list_length(cib->notify_list)); crm_malloc0(new_client, sizeof(cib_notify_client_t)); new_client->event = event; new_client->callback = callback; list_item = g_list_find_custom( cib->notify_list, new_client, ciblib_GCompareFunc); if(list_item != NULL) { crm_warn("Callback already present"); } else { cib->notify_list = g_list_append( cib->notify_list, new_client); cib->cmds->register_callback(cib, event, 1); crm_debug_3("Callback added (%d)", g_list_length(cib->notify_list)); } return cib_ok; } int cib_client_del_notify_callback( cib_t *cib, const char *event, void (*callback)( const char *event, struct ha_msg *msg)) { GList *list_item = NULL; cib_notify_client_t *new_client = NULL; crm_debug("Removing callback for %s events", event); crm_malloc0(new_client, sizeof(cib_notify_client_t)); new_client->event = event; new_client->callback = callback; list_item = g_list_find_custom( cib->notify_list, new_client, ciblib_GCompareFunc); cib->cmds->register_callback(cib, event, 0); if(list_item != NULL) { cib_notify_client_t *list_client = list_item->data; cib->notify_list = g_list_remove(cib->notify_list, list_client); crm_free(list_client); crm_debug_3("Removed callback"); } else { crm_debug_3("Callback not present"); } crm_free(new_client); return cib_ok; } gint ciblib_GCompareFunc(gconstpointer a, gconstpointer b) { const cib_notify_client_t *a_client = a; const cib_notify_client_t *b_client = b; if(a_client->callback == b_client->callback && safe_str_neq(a_client->event, b_client->event)) { return 0; } else if(((long)a_client->callback) < ((long)b_client->callback)) { return -1; } return 1; } gboolean add_cib_op_callback( int call_id, gboolean only_success, void *user_data, void (*callback)(const HA_Message*, int, int, crm_data_t*,void*)) { cib_callback_client_t *blob = NULL; if(call_id < 0) { crm_warn("CIB call failed: %s", cib_error2string(call_id)); if(only_success == FALSE) { callback(NULL, call_id, call_id, NULL, user_data); } return FALSE; } crm_malloc0(blob, sizeof(cib_callback_client_t)); blob->only_success = only_success; blob->user_data = user_data; blob->callback = callback; g_hash_table_insert( cib_op_callback_table, GINT_TO_POINTER(call_id), blob); return TRUE; } void remove_cib_op_callback(int call_id, gboolean all_callbacks) { if(all_callbacks) { if(cib_op_callback_table != NULL) { g_hash_table_destroy(cib_op_callback_table); } cib_op_callback_table = g_hash_table_new_full( g_direct_hash, g_direct_equal, NULL, g_hash_destroy_str); } else { g_hash_table_remove( cib_op_callback_table, GINT_TO_POINTER(call_id)); } } int num_cib_op_callbacks(void) { if(cib_op_callback_table == NULL) { return 0; } return g_hash_table_size(cib_op_callback_table); } char * cib_pluralSection(const char *a_section) { char *a_section_parent = NULL; if (a_section == NULL) { a_section_parent = crm_strdup("all"); } else if(strcmp(a_section, XML_TAG_CIB) == 0) { a_section_parent = crm_strdup("all"); } else if(strcmp(a_section, XML_CIB_TAG_NODE) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_NODES); } else if(strcmp(a_section, XML_CIB_TAG_STATE) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_STATUS); } else if(strcmp(a_section, XML_CIB_TAG_CONSTRAINT) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS); } else if(strcmp(a_section, XML_CONS_TAG_RSC_LOCATION) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS); } else if(strcmp(a_section, XML_CONS_TAG_RSC_DEPEND) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS); } else if(strcmp(a_section, XML_CONS_TAG_RSC_ORDER) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS); } else if(strcmp(a_section, "resource") == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_RESOURCES); } else if(strcmp(a_section, XML_CIB_TAG_RESOURCE) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_RESOURCES); } else if(strcmp(a_section, XML_CIB_TAG_GROUP) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_RESOURCES); } else if(strcmp(a_section, XML_CIB_TAG_INCARNATION) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_RESOURCES); } else if(strcmp(a_section, XML_CIB_TAG_NVPAIR) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_CRMCONFIG); } else if(strcmp(a_section, XML_TAG_ATTR_SETS) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_CRMCONFIG); } else { crm_err("Unknown section %s", a_section); a_section_parent = crm_strdup("all"); } crm_debug_2("Plural of %s is %s", crm_str(a_section), a_section_parent); return a_section_parent; } const char * cib_error2string(enum cib_errors return_code) { const char *error_msg = NULL; switch(return_code) { case cib_msg_field_add: error_msg = "failed adding field to cib message"; break; case cib_id_check: error_msg = "id-collision detected"; break; case cib_operation: error_msg = "invalid operation"; break; case cib_create_msg: error_msg = "couldnt create cib message"; break; case cib_client_gone: error_msg = "client left before we could send reply"; break; case cib_not_connected: error_msg = "not connected"; break; case cib_not_authorized: error_msg = "not authorized"; break; case cib_send_failed: error_msg = "send failed"; break; case cib_reply_failed: error_msg = "reply failed"; break; case cib_return_code: error_msg = "no return code"; break; case cib_output_ptr: error_msg = "nowhere to store output"; break; case cib_output_data: error_msg = "corrupt output data"; break; case cib_connection: error_msg = "connection failed"; break; case cib_callback_register: error_msg = "couldnt register callback channel"; break; case cib_authentication: error_msg = ""; break; case cib_registration_msg: error_msg = "invalid registration msg"; break; case cib_callback_token: error_msg = "callback token not found"; break; case cib_missing: error_msg = "cib object missing"; break; case cib_variant: error_msg = "unknown/corrupt cib variant"; break; case CIBRES_MISSING_ID: error_msg = "The id field is missing"; break; case CIBRES_MISSING_TYPE: error_msg = "The type field is missing"; break; case CIBRES_MISSING_FIELD: error_msg = "A required field is missing"; break; case CIBRES_OBJTYPE_MISMATCH: error_msg = "CIBRES_OBJTYPE_MISMATCH"; break; case cib_EXISTS: error_msg = "The object already exists"; break; case cib_NOTEXISTS: error_msg = "The object does not exist"; break; case CIBRES_CORRUPT: error_msg = "The CIB is corrupt"; break; case cib_NOOBJECT: error_msg = "The update was empty"; break; case cib_NOPARENT: error_msg = "The parent object does not exist"; break; case cib_NODECOPY: error_msg = "Failed while copying update"; break; case CIBRES_OTHER: error_msg = "CIBRES_OTHER"; break; case cib_ok: error_msg = "ok"; break; case cib_unknown: error_msg = "Unknown error"; break; case cib_STALE: error_msg = "Discarded old update"; break; case cib_ACTIVATION: error_msg = "Activation Failed"; break; case cib_NOSECTION: error_msg = "Required section was missing"; break; case cib_NOTSUPPORTED: error_msg = "Supplied information is not supported"; break; case cib_not_master: error_msg = "Local service is not the master instance"; break; case cib_client_corrupt: error_msg = "Service client not valid"; break; case cib_remote_timeout: error_msg = "Remote node did not respond"; break; case cib_master_timeout: error_msg = "No master service is currently active"; break; case cib_revision_unsupported: error_msg = "The required CIB revision number is not supported"; break; case cib_revision_unknown: error_msg = "The CIB revision number could not be determined"; break; case cib_missing_data: error_msg = "Required data for this CIB API call not found"; break; case cib_no_quorum: error_msg = "Write requires quorum"; break; case cib_diff_failed: error_msg = "Application of an update diff failed"; break; case cib_diff_resync: error_msg = "Application of an update diff failed, requesting a full refresh"; break; case cib_old_data: error_msg = "Update was older than existing configuration"; break; } if(error_msg == NULL) { crm_err("Unknown CIB Error Code: %d", return_code); error_msg = ""; } return error_msg; } const char * cib_op2string(enum cib_update_op operation) { const char *operation_msg = NULL; switch(operation) { case 0: operation_msg = "none"; break; case 1: operation_msg = "add"; break; case 2: operation_msg = "modify"; break; case 3: operation_msg = "delete"; break; case CIB_UPDATE_OP_MAX: operation_msg = "invalid operation"; break; } if(operation_msg == NULL) { crm_err("Unknown CIB operation %d", operation); operation_msg = ""; } return operation_msg; } int cib_section2enum(const char *a_section) { if(a_section == NULL || strcmp(a_section, "all") == 0) { return cib_section_all; } else if(strcmp(a_section, XML_CIB_TAG_NODES) == 0) { return cib_section_nodes; } else if(strcmp(a_section, XML_CIB_TAG_STATUS) == 0) { return cib_section_status; } else if(strcmp(a_section, XML_CIB_TAG_CONSTRAINTS) == 0) { return cib_section_constraints; } else if(strcmp(a_section, XML_CIB_TAG_RESOURCES) == 0) { return cib_section_resources; } else if(strcmp(a_section, XML_CIB_TAG_CRMCONFIG) == 0) { return cib_section_crmconfig; } crm_err("Unknown CIB section: %s", a_section); return cib_section_none; } int cib_compare_generation(crm_data_t *left, crm_data_t *right) { int lpc = 0; const char *attributes[] = { XML_ATTR_GENERATION_ADMIN, XML_ATTR_GENERATION, XML_ATTR_NUMUPDATES, XML_ATTR_NUMPEERS }; crm_log_xml_debug_3(left, "left"); crm_log_xml_debug_3(right, "right"); for(lpc = 0; lpc < DIMOF(attributes); lpc++) { int int_elem_l = -1; int int_elem_r = -1; const char *elem_r = NULL; const char *elem_l = crm_element_value(left, attributes[lpc]); if(right != NULL) { elem_r = crm_element_value(right, attributes[lpc]); } if(elem_l != NULL) { int_elem_l = crm_parse_int(elem_l, NULL); } if(elem_r != NULL) { int_elem_r = crm_parse_int(elem_r, NULL); } if(int_elem_l < int_elem_r) { crm_debug_2("%s (%s < %s)", attributes[lpc], crm_str(elem_l), crm_str(elem_r)); return -1; } else if(int_elem_l > int_elem_r) { crm_debug_2("%s (%s > %s)", attributes[lpc], crm_str(elem_l), crm_str(elem_r)); return 1; } } return 0; } crm_data_t* get_cib_copy(cib_t *cib) { crm_data_t *xml_cib; crm_data_t *xml_cib_copy; int options = cib_scope_local|cib_sync_call; if(cib->cmds->query(cib, NULL, &xml_cib, options) != cib_ok) { crm_err("Couldnt retrieve the CIB"); return NULL; } else if(xml_cib == NULL) { crm_err("The CIB result was empty"); return NULL; } if(safe_str_eq(crm_element_name(xml_cib), XML_TAG_CIB)) { return xml_cib; #if CRM_DEPRECATED_SINCE_2_0_4 } else { xml_cib_copy = copy_xml( find_xml_node(xml_cib, XML_TAG_CIB, TRUE)); free_xml(xml_cib); return xml_cib_copy; #endif } free_xml(xml_cib); return NULL; } crm_data_t* cib_get_generation(cib_t *cib) { crm_data_t *the_cib = get_cib_copy(cib); crm_data_t *generation = create_xml_node( NULL, XML_CIB_TAG_GENERATION_TUPPLE); if(the_cib != NULL) { copy_in_properties(generation, the_cib); free_xml(the_cib); } return generation; } gboolean apply_cib_diff(crm_data_t *old, crm_data_t *diff, crm_data_t **new) { gboolean result = TRUE; const char *value = NULL; int this_updates = 0; int this_epoch = 0; int this_admin_epoch = 0; int diff_add_updates = 0; int diff_add_epoch = 0; int diff_add_admin_epoch = 0; int diff_del_updates = 0; int diff_del_epoch = 0; int diff_del_admin_epoch = 0; - CRM_DEV_ASSERT(diff != NULL); - CRM_DEV_ASSERT(old != NULL); + CRM_CHECK(diff != NULL, return FALSE); + CRM_CHECK(old != NULL, return FALSE); value = crm_element_value(old, XML_ATTR_GENERATION_ADMIN); this_admin_epoch = crm_parse_int(value, "0"); crm_debug_3("%s=%d (%s)", XML_ATTR_GENERATION_ADMIN, this_admin_epoch, value); value = crm_element_value(old, XML_ATTR_GENERATION); this_epoch = crm_parse_int(value, "0"); crm_debug_3("%s=%d (%s)", XML_ATTR_GENERATION, this_epoch, value); value = crm_element_value(old, XML_ATTR_NUMUPDATES); this_updates = crm_parse_int(value, "0"); crm_debug_3("%s=%d (%s)", XML_ATTR_NUMUPDATES, this_updates, value); cib_diff_version_details( diff, &diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates, &diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates); value = NULL; if(result && diff_del_admin_epoch != this_admin_epoch) { value = XML_ATTR_GENERATION_ADMIN; result = FALSE; crm_debug_3("%s=%d", value, diff_del_admin_epoch); } else if(result && diff_del_epoch != this_epoch) { value = XML_ATTR_GENERATION; result = FALSE; crm_debug_3("%s=%d", value, diff_del_epoch); } else if(result && diff_del_updates != this_updates) { value = XML_ATTR_NUMUPDATES; result = FALSE; crm_debug_3("%s=%d", value, diff_del_updates); } if(result) { int len = 0; crm_data_t *tmp = NULL; crm_data_t *diff_copy = copy_xml(diff); tmp = find_xml_node(diff_copy, "diff-removed", TRUE); if(tmp != NULL) { len = tmp->nfields; cl_msg_remove(tmp, XML_ATTR_GENERATION_ADMIN); cl_msg_remove(tmp, XML_ATTR_GENERATION); cl_msg_remove(tmp, XML_ATTR_NUMUPDATES); - CRM_DEV_ASSERT(tmp->nfields == len - 3); } tmp = find_xml_node(diff_copy, "diff-added", TRUE); if(tmp != NULL) { len = tmp->nfields; cl_msg_remove(tmp, XML_ATTR_GENERATION_ADMIN); cl_msg_remove(tmp, XML_ATTR_GENERATION); cl_msg_remove(tmp, XML_ATTR_NUMUPDATES); - CRM_DEV_ASSERT(tmp->nfields == len - 3); } result = apply_xml_diff(old, diff_copy, new); free_xml(diff_copy); } else { crm_err("target and diff %s values didnt match", value); } return result; } crm_data_t * diff_cib_object(crm_data_t *old_cib, crm_data_t *new_cib, gboolean suppress) { crm_data_t *diff = diff_xml_object(old_cib, new_cib, suppress); crm_data_t *dest = NULL; crm_data_t *src = NULL; const char *name = NULL; const char *value = NULL; /* add complete version information */ src = old_cib; dest = find_xml_node(diff, "diff-removed", FALSE); if(src != NULL && dest != NULL) { name = XML_ATTR_GENERATION_ADMIN; value = crm_element_value(src, name); if(value == NULL) { value = "0"; } crm_xml_add(dest, name, value); name = XML_ATTR_GENERATION; value = crm_element_value(src, name); if(value == NULL) { value = "0"; } crm_xml_add(dest, name, value); name = XML_ATTR_NUMUPDATES; value = crm_element_value(src, name); if(value == NULL) { value = "0"; } crm_xml_add(dest, name, value); } src = new_cib; dest = find_xml_node(diff, "diff-added", FALSE); if(src != NULL && dest != NULL) { name = XML_ATTR_GENERATION_ADMIN; value = crm_element_value(src, name); if(value == NULL) { value = "0"; } crm_xml_add(dest, name, value); name = XML_ATTR_GENERATION; value = crm_element_value(src, name); if(value == NULL) { value = "0"; } crm_xml_add(dest, name, value); name = XML_ATTR_NUMUPDATES; value = crm_element_value(src, name); if(value == NULL) { value = "0"; } crm_xml_add(dest, name, value); } return diff; } void log_cib_diff(int log_level, crm_data_t *diff, const char *function) { int add_updates = 0; int add_epoch = 0; int add_admin_epoch = 0; int del_updates = 0; int del_epoch = 0; int del_admin_epoch = 0; if(diff == NULL) { return; } cib_diff_version_details( diff, &add_admin_epoch, &add_epoch, &add_updates, &del_admin_epoch, &del_epoch, &del_updates); if(add_updates != del_updates) { do_crm_log(log_level, NULL, function, "Diff: --- %d.%d.%d", del_admin_epoch, del_epoch, del_updates); do_crm_log(log_level, NULL, function, "Diff: +++ %d.%d.%d", add_admin_epoch, add_epoch, add_updates); } else if(diff != NULL) { do_crm_log(log_level, NULL, function, "Local-only Change: %d.%d.%d", add_admin_epoch, add_epoch, add_updates); } log_xml_diff(log_level, diff, function); } gboolean cib_version_details( crm_data_t *cib, int *admin_epoch, int *epoch, int *updates) { const char *value = NULL; if(cib == NULL) { *admin_epoch = -1; *epoch = -1; *updates = -1; return FALSE; } else { value = crm_element_value(cib, XML_ATTR_GENERATION_ADMIN); *admin_epoch = crm_parse_int(value, "-1"); value = crm_element_value(cib, XML_ATTR_GENERATION); *epoch = crm_parse_int(value, "-1"); value = crm_element_value(cib, XML_ATTR_NUMUPDATES); *updates = crm_parse_int(value, "-1"); } return TRUE; } gboolean cib_diff_version_details( crm_data_t *diff, int *admin_epoch, int *epoch, int *updates, int *_admin_epoch, int *_epoch, int *_updates) { crm_data_t *tmp = NULL; tmp = find_xml_node(diff, "diff-added", FALSE); cib_version_details(tmp, admin_epoch, epoch, updates); tmp = find_xml_node(diff, "diff-removed", FALSE); cib_version_details(tmp, _admin_epoch, _epoch, _updates); return TRUE; } /* * The caller should never free the return value */ crm_data_t* get_object_root(const char *object_type, crm_data_t *the_root) { const char *node_stack[2]; crm_data_t *tmp_node = NULL; if(the_root == NULL) { crm_err("CIB root object was NULL"); return NULL; } node_stack[0] = XML_CIB_TAG_CONFIGURATION; node_stack[1] = object_type; if(object_type == NULL || strlen(object_type) == 0 || safe_str_eq(XML_CIB_TAG_SECTION_ALL, object_type) || safe_str_eq(XML_TAG_CIB, object_type)) { /* get the whole cib */ return the_root; } else if(strcmp(object_type, XML_CIB_TAG_STATUS) == 0) { /* these live in a different place */ tmp_node = find_xml_node(the_root, XML_CIB_TAG_STATUS, FALSE); node_stack[0] = object_type; node_stack[1] = NULL; } else { tmp_node = find_xml_node_nested(the_root, node_stack, 2); } if (tmp_node == NULL) { crm_debug_2("Section [%s [%s]] not present in %s", node_stack[0], node_stack[1]?node_stack[1]:"", crm_element_name(the_root)); } return tmp_node; } const char * get_crm_option(crm_data_t *cib, const char *name, gboolean do_warn) { const char * value = NULL; crm_data_t * a_default = NULL; crm_data_t * config = get_object_root(XML_CIB_TAG_CRMCONFIG, cib); if(config != NULL) { a_default = find_entity(config, XML_CIB_TAG_NVPAIR, name); } if(a_default == NULL) { if(do_warn) { crm_warn("Option %s not set", name); } return NULL; } value = crm_element_value(a_default, XML_NVPAIR_ATTR_VALUE); if(safe_str_eq(value, "")) { value = NULL; } return value; } crm_data_t* create_cib_fragment_adv( crm_data_t *update, const char *update_section, const char *source) { crm_data_t *cib = NULL; gboolean whole_cib = FALSE; crm_data_t *object_root = NULL; const char *update_name = NULL; /* crm_debug("Creating a blank fragment: %s", update_section); */ if(update == NULL && update_section == NULL) { crm_debug_3("Creating a blank fragment"); update = createEmptyCib(); crm_xml_add(cib, "debug_source", source); return update; } else if(update == NULL) { crm_err("No update to create a fragment for"); return NULL; } else if(update_section == NULL) { update_section = cib_pluralSection(update_name); } if(safe_str_eq(crm_element_name(update), XML_TAG_CIB)) { whole_cib = TRUE; } if(whole_cib == FALSE) { cib = createEmptyCib(); crm_xml_add(cib, "debug_source", source); object_root = get_object_root(update_section, cib); add_node_copy(object_root, update); } else { cib = copy_xml(update); crm_xml_add(cib, "debug_source", source); } crm_debug_3("Verifying created fragment"); if(verifyCibXml(cib) == FALSE) { crm_err("Fragment creation failed"); crm_log_xml_err(cib, "[src]"); free_xml(cib); cib = NULL; } return cib; } /* * It is the callers responsibility to free both the new CIB (output) * and the new CIB (input) */ crm_data_t* createEmptyCib(void) { crm_data_t *cib_root = NULL, *config = NULL, *status = NULL; cib_root = create_xml_node(NULL, XML_TAG_CIB); config = create_xml_node(cib_root, XML_CIB_TAG_CONFIGURATION); status = create_xml_node(cib_root, XML_CIB_TAG_STATUS); set_node_tstamp(cib_root); set_node_tstamp(config); set_node_tstamp(status); /* crm_xml_add(cib_root, "version", "1"); */ crm_xml_add(cib_root, "generated", XML_BOOLEAN_TRUE); create_xml_node(config, XML_CIB_TAG_CRMCONFIG); create_xml_node(config, XML_CIB_TAG_NODES); create_xml_node(config, XML_CIB_TAG_RESOURCES); create_xml_node(config, XML_CIB_TAG_CONSTRAINTS); if (verifyCibXml(cib_root)) { return cib_root; } free_xml(cib_root); crm_crit("The generated CIB did not pass integrity testing!!" " All hope is lost."); return NULL; } gboolean verifyCibXml(crm_data_t *cib) { gboolean is_valid = TRUE; crm_data_t *tmp_node = NULL; if (cib == NULL) { crm_warn("CIB was empty."); return FALSE; } tmp_node = get_object_root(XML_CIB_TAG_NODES, cib); if (tmp_node == NULL) { is_valid = FALSE; } tmp_node = get_object_root(XML_CIB_TAG_RESOURCES, cib); if (tmp_node == NULL) { is_valid = FALSE; } tmp_node = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); if (tmp_node == NULL) { is_valid = FALSE; } tmp_node = get_object_root(XML_CIB_TAG_STATUS, cib); if (tmp_node == NULL) { is_valid = FALSE; } tmp_node = get_object_root(XML_CIB_TAG_CRMCONFIG, cib); if (tmp_node == NULL) { is_valid = FALSE; } /* more integrity tests */ return is_valid; } gboolean verify_cib_cmds(cib_t *cib) { gboolean valid = TRUE; if(cib->cmds->variant_op == NULL) { crm_err("Operation variant_op not set"); valid = FALSE; } if(cib->cmds->signon == NULL) { crm_err("Operation signon not set"); valid = FALSE; } if(cib->cmds->signoff == NULL) { crm_err("Operation signoff not set"); valid = FALSE; } if(cib->cmds->free == NULL) { crm_err("Operation free not set"); valid = FALSE; } if(cib->cmds->set_op_callback == NULL) { crm_err("Operation set_op_callback not set"); valid = FALSE; } if(cib->cmds->add_notify_callback == NULL) { crm_err("Operation add_notify_callback not set"); valid = FALSE; } if(cib->cmds->del_notify_callback == NULL) { crm_err("Operation del_notify_callback not set"); valid = FALSE; } if(cib->cmds->set_connection_dnotify == NULL) { crm_err("Operation set_connection_dnotify not set"); valid = FALSE; } if(cib->cmds->channel == NULL) { crm_err("Operation channel not set"); valid = FALSE; } if(cib->cmds->inputfd == NULL) { crm_err("Operation inputfd not set"); valid = FALSE; } if(cib->cmds->noop == NULL) { crm_err("Operation noop not set"); valid = FALSE; } if(cib->cmds->ping == NULL) { crm_err("Operation ping not set"); valid = FALSE; } if(cib->cmds->query == NULL) { crm_err("Operation query not set"); valid = FALSE; } if(cib->cmds->query_from == NULL) { crm_err("Operation query_from not set"); valid = FALSE; } if(cib->cmds->is_master == NULL) { crm_err("Operation is_master not set"); valid = FALSE; } if(cib->cmds->set_master == NULL) { crm_err("Operation set_master not set"); valid = FALSE; } if(cib->cmds->set_slave == NULL) { crm_err("Operation set_slave not set"); valid = FALSE; } if(cib->cmds->set_slave_all == NULL) { crm_err("Operation set_slave_all not set"); valid = FALSE; } if(cib->cmds->sync == NULL) { crm_err("Operation sync not set"); valid = FALSE; } if(cib->cmds->sync_from == NULL) { crm_err("Operation sync_from not set"); valid = FALSE; } if(cib->cmds->bump_epoch == NULL) { crm_err("Operation bump_epoch not set"); valid = FALSE; } if(cib->cmds->create == NULL) { crm_err("Operation create not set"); valid = FALSE; } if(cib->cmds->modify == NULL) { crm_err("Operation modify not set"); valid = FALSE; } if(cib->cmds->replace == NULL) { crm_err("Operation replace not set"); valid = FALSE; } if(cib->cmds->delete == NULL) { crm_err("Operation delete not set"); valid = FALSE; } if(cib->cmds->erase == NULL) { crm_err("Operation erase not set"); valid = FALSE; } if(cib->cmds->quit == NULL) { crm_err("Operation quit not set"); valid = FALSE; } if(cib->cmds->msgready == NULL) { crm_err("Operation msgready not set"); valid = FALSE; } if(cib->cmds->rcvmsg == NULL) { crm_err("Operation rcvmsg not set"); valid = FALSE; } if(cib->cmds->dispatch == NULL) { crm_err("Operation dispatch not set"); valid = FALSE; } return valid; } diff --git a/lib/crm/cib/cib_native.c b/lib/crm/cib/cib_native.c index 996d56488e..fe3f1b27ce 100755 --- a/lib/crm/cib/cib_native.c +++ b/lib/crm/cib/cib_native.c @@ -1,842 +1,843 @@ /* * Copyright (c) 2004 International Business Machines * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser 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 library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 typedef struct cib_native_opaque_s { IPC_Channel *command_channel; IPC_Channel *callback_channel; GCHSource *callback_source; } cib_native_opaque_t; int cib_native_perform_op( cib_t *cib, const char *op, const char *host, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options); int cib_native_signon(cib_t* cib, const char *name, enum cib_conn_type type); int cib_native_signoff(cib_t* cib); int cib_native_free(cib_t* cib); IPC_Channel *cib_native_channel(cib_t* cib); int cib_native_inputfd(cib_t* cib); gboolean cib_native_msgready(cib_t* cib); int cib_native_rcvmsg(cib_t* cib, int blocking); gboolean cib_native_dispatch(IPC_Channel *channel, gpointer user_data); cib_t *cib_native_new (cib_t *cib); void cib_native_delete(cib_t *cib); int cib_native_set_connection_dnotify( cib_t *cib, void (*dnotify)(gpointer user_data)); void cib_native_notify(gpointer data, gpointer user_data); void cib_native_callback(cib_t *cib, struct ha_msg *msg); int cib_native_register_callback(cib_t* cib, const char *callback, int enabled); cib_t* cib_native_new (cib_t *cib) { cib_native_opaque_t *native = NULL; crm_malloc0(cib->variant_opaque, sizeof(cib_native_opaque_t)); native = cib->variant_opaque; native->command_channel = NULL; native->callback_channel = NULL; /* assign variant specific ops*/ cib->cmds->variant_op = cib_native_perform_op; cib->cmds->signon = cib_native_signon; cib->cmds->signoff = cib_native_signoff; cib->cmds->free = cib_native_free; cib->cmds->channel = cib_native_channel; cib->cmds->inputfd = cib_native_inputfd; cib->cmds->msgready = cib_native_msgready; cib->cmds->rcvmsg = cib_native_rcvmsg; cib->cmds->dispatch = cib_native_dispatch; cib->cmds->register_callback = cib_native_register_callback; cib->cmds->set_connection_dnotify = cib_native_set_connection_dnotify; return cib; } void cib_native_delete(cib_t *cib) { crm_free(cib->variant_opaque); } int cib_native_signon(cib_t* cib, const char *name, enum cib_conn_type type) { int rc = cib_ok; char *uuid_ticket = NULL; struct ha_msg *reg_msg = NULL; cib_native_opaque_t *native = cib->variant_opaque; crm_debug_4("Connecting command channel"); if(type == cib_command) { cib->state = cib_connected_command; native->command_channel = init_client_ipc_comms_nodispatch( cib_channel_rw); } else if(type == cib_query) { cib->state = cib_connected_query; native->command_channel = init_client_ipc_comms_nodispatch( cib_channel_ro); } else if(type == cib_query_synchronous) { cib->state = cib_connected_query; native->command_channel = init_client_ipc_comms_nodispatch( cib_channel_ro_synchronous); } else if(type == cib_command_synchronous) { cib->state = cib_connected_query; native->command_channel = init_client_ipc_comms_nodispatch( cib_channel_rw_synchronous); } else { return cib_not_connected; } if(native->command_channel == NULL) { crm_debug("Connection to command channel failed"); rc = cib_connection; } else if(native->command_channel->ch_status != IPC_CONNECT) { crm_err("Connection may have succeeded," " but authentication to command channel failed"); rc = cib_authentication; } if(type == cib_query_synchronous || type == cib_command_synchronous) { return rc; } if(rc == cib_ok) { crm_debug_4("Connecting callback channel"); native->callback_source = init_client_ipc_comms( cib_channel_callback, cib_native_dispatch, cib, &(native->callback_channel)); if(native->callback_channel == NULL) { crm_debug("Connection to callback channel failed"); rc = cib_connection; } else if(native->callback_source == NULL) { crm_err("Callback source not recorded"); rc = cib_connection; } else { native->callback_channel->send_queue->max_qlen = 500; } } else if(rc == cib_ok && native->callback_channel->ch_status != IPC_CONNECT) { crm_err("Connection may have succeeded," " but authentication to callback channel failed"); rc = cib_authentication; } if(rc == cib_ok) { crm_debug_4("Waiting for msg on command channel"); reg_msg = msgfromIPC(native->command_channel, MSG_ALLOWINTR); if(native->command_channel->ops->get_chan_status( native->command_channel) != IPC_CONNECT) { crm_err("No reply message - disconnected - %d", rc); rc = cib_not_connected; } else if(rc != IPC_OK) { crm_err("No reply message - failed - %d", rc); rc = cib_reply_failed; } else if(reg_msg == NULL) { crm_err("No reply message - empty - %d", rc); rc = cib_reply_failed; } } if(rc == cib_ok) { const char *msg_type = NULL; msg_type = cl_get_string(reg_msg, F_CIB_OPERATION); if(safe_str_neq(msg_type, CRM_OP_REGISTER) ) { crm_err("Invalid registration message: %s", msg_type); rc = cib_registration_msg; } else { const char *tmp_ticket = NULL; crm_debug_4("Retrieving callback channel ticket"); tmp_ticket = cl_get_string( reg_msg, F_CIB_CALLBACK_TOKEN); if(tmp_ticket == NULL) { rc = cib_callback_token; } else { uuid_ticket = crm_strdup(tmp_ticket); } } } if(reg_msg != NULL) { crm_msg_del(reg_msg); reg_msg = NULL; } if(rc == cib_ok) { crm_debug_4("Registering callback channel with ticket %s", crm_str(uuid_ticket)); reg_msg = ha_msg_new(2); ha_msg_add(reg_msg, F_CIB_OPERATION, CRM_OP_REGISTER); ha_msg_add(reg_msg, F_CIB_CALLBACK_TOKEN, uuid_ticket); ha_msg_add(reg_msg, F_CIB_CLIENTNAME, name); if(send_ipc_message( native->callback_channel, reg_msg) == FALSE) { rc = cib_callback_register; } crm_free(uuid_ticket); } if(rc == cib_ok) { /* In theory IPC_INTR could trip us up here */ crm_debug_4("wait for the callback channel setup to complete"); reg_msg = msgfromIPC(native->callback_channel, MSG_ALLOWINTR); if(native->callback_channel->ops->get_chan_status( native->callback_channel) != IPC_CONNECT) { crm_err("No reply message - disconnected - %d", rc); rc = cib_not_connected; } else if(rc != IPC_OK) { crm_err("No reply message - failed - %d", rc); rc = cib_reply_failed; } else if(reg_msg == NULL) { crm_err("No reply message - empty - %d", rc); rc = cib_reply_failed; } crm_msg_del(reg_msg); } if(rc == cib_ok) { crm_debug("Connection to CIB successful"); return cib_ok; } crm_warn("Connection to CIB failed: %s", cib_error2string(rc)); cib_native_signoff(cib); return rc; } int cib_native_signoff(cib_t* cib) { cib_native_opaque_t *native = cib->variant_opaque; crm_debug("Signing out of the CIB Service"); /* close channels */ if (native->command_channel != NULL) { native->command_channel->ops->destroy( native->command_channel); native->command_channel = NULL; } if (native->callback_channel != NULL) { G_main_del_IPC_Channel(native->callback_source); #ifdef BUG native->callback_channel->ops->destroy( native->callback_channel); #endif native->callback_channel = NULL; } cib->state = cib_disconnected; cib->type = cib_none; return cib_ok; } int cib_native_free (cib_t* cib) { int rc = cib_ok; crm_warn("Freeing CIB"); if(cib->state != cib_disconnected) { rc = cib_native_signoff(cib); if(rc == cib_ok) { crm_free(cib); } } return rc; } IPC_Channel * cib_native_channel(cib_t* cib) { cib_native_opaque_t *native = NULL; if(cib == NULL) { crm_err("Missing cib object"); return NULL; } native = cib->variant_opaque; if(native != NULL) { return native->callback_channel; } crm_err("couldnt find variant specific data in %p", cib); return NULL; } int cib_native_inputfd(cib_t* cib) { IPC_Channel *ch = cib_native_channel(cib); return ch->ops->get_recv_select_fd(ch); } static HA_Message * cib_create_op( int call_id, const char *op, const char *host, const char *section, crm_data_t *data, int call_options) { int rc = HA_OK; HA_Message *op_msg = NULL; op_msg = ha_msg_new(8); if (op_msg == NULL) { crm_err("No memory to create HA_Message"); return NULL; } if(rc == HA_OK) { rc = ha_msg_add(op_msg, F_TYPE, T_CIB); } if(rc == HA_OK) { rc = ha_msg_add(op_msg, F_CIB_OPERATION, op); } if(rc == HA_OK && host != NULL) { rc = ha_msg_add(op_msg, F_CIB_HOST, host); } if(rc == HA_OK && section != NULL) { rc = ha_msg_add(op_msg, F_CIB_SECTION, section); } if(rc == HA_OK) { rc = ha_msg_add_int(op_msg, F_CIB_CALLID, call_id); } if(rc == HA_OK) { crm_debug_4("Sending call options: %.8lx, %d", (long)call_options, call_options); rc = ha_msg_add_int(op_msg, F_CIB_CALLOPTS, call_options); } #if 0 if(rc == HA_OK && cib->call_timeout > 0) { rc = ha_msg_add_int(op_msg, F_CIB_TIMEOUT, cib->call_timeout); } #endif if(rc == HA_OK && data != NULL) { #if 0 const char *tag = crm_element_name(data); crm_data_t *cib = data; if(safe_str_neq(tag, XML_TAG_CIB)) { cib = find_xml_node(data, XML_TAG_CIB, FALSE); if(cib != NULL) { tag = XML_TAG_CIB; } } if(safe_str_eq(tag, XML_TAG_CIB)) { const char *version = feature_set(cib); crm_xml_add(cib, XML_ATTR_CIB_REVISION, version); } else { crm_info("Skipping feature check for %s tag", tag); } #endif add_message_xml(op_msg, F_CIB_CALLDATA, data); } if (rc != HA_OK) { crm_err("Failed to create CIB operation message"); crm_log_message(LOG_ERR, op_msg); crm_msg_del(op_msg); return NULL; } if(call_options & cib_inhibit_bcast) { - CRM_DEV_ASSERT((call_options & cib_scope_local)); + CRM_CHECK((call_options & cib_scope_local), return NULL); } return op_msg; } int cib_native_perform_op( cib_t *cib, const char *op, const char *host, const char *section, crm_data_t *data, crm_data_t **output_data, int call_options) { int rc = HA_OK; struct ha_msg *op_msg = NULL; struct ha_msg *op_reply = NULL; cib_native_opaque_t *native = cib->variant_opaque; if(cib->state == cib_disconnected) { return cib_not_connected; } if(output_data != NULL) { *output_data = NULL; } if(op == NULL) { crm_err("No operation specified"); return cib_operation; } cib->call_id++; /* prevent call_id from being negative (or zero) and conflicting * with the cib_errors enum * use 2 because we use it as (cib->call_id - 1) below */ if(cib->call_id < 1) { cib->call_id = 1; } op_msg = cib_create_op( cib->call_id, op, host, section, data, call_options); if(op_msg == NULL) { return cib_create_msg; } crm_debug_3("Sending %s message to CIB service", op); if(send_ipc_message(native->command_channel, op_msg) == FALSE) { crm_err("Sending message to CIB service FAILED"); return cib_send_failed; } else { crm_debug_3("Message sent"); } op_msg = NULL; if((call_options & cib_discard_reply)) { crm_debug_3("Discarding reply"); return cib_ok; } else if(!(call_options & cib_sync_call)) { crm_debug_3("Async call, returning"); - CRM_DEV_ASSERT(cib->call_id != 0); + CRM_CHECK(cib->call_id != 0, return cib_reply_failed); return cib->call_id; } rc = IPC_OK; crm_debug_3("Waiting for a syncronous reply"); while(IPC_ISRCONN(native->command_channel)) { int reply_id = -1; int msg_id = cib->call_id; op_reply = msgfromIPC(native->command_channel, MSG_ALLOWINTR); if(op_reply == NULL) { break; } - CRM_DEV_ASSERT(HA_OK == ha_msg_value_int( - op_reply, F_CIB_CALLID, &reply_id)); + CRM_CHECK(ha_msg_value_int( + op_reply, F_CIB_CALLID, &reply_id) == HA_OK, + return cib_reply_failed); - CRM_DEV_ASSERT(reply_id <= msg_id); + CRM_CHECK(reply_id <= msg_id, return cib_reply_failed); if(reply_id == msg_id) { break; } else if(reply_id < msg_id) { crm_debug("Recieved old reply: %d (wanted %d)", reply_id, msg_id); crm_log_message_adv( LOG_MSG, "Old reply", op_reply); } else if((reply_id - 10000) > msg_id) { /* wrap-around case */ crm_debug("Recieved old reply: %d (wanted %d)", reply_id, msg_id); crm_log_message_adv( LOG_MSG, "Old reply", op_reply); } else { crm_err("Received a __future__ reply:" " %d (wanted %d)", reply_id, msg_id); } crm_msg_del(op_reply); op_reply = NULL; } if(op_reply == NULL) { if(IPC_ISRCONN(native->command_channel) == FALSE) { crm_err("No reply message - disconnected - %d", native->command_channel->ch_status); cib->state = cib_disconnected; return cib_not_connected; } crm_err("No reply message - empty - %d", rc); return cib_reply_failed; } if(IPC_ISRCONN(native->command_channel) == FALSE) { crm_err("CIB disconnected: %d", native->command_channel->ch_status); cib->state = cib_disconnected; } crm_debug_3("Syncronous reply recieved"); rc = cib_ok; /* Start processing the reply... */ if(ha_msg_value_int(op_reply, F_CIB_RC, &rc) != HA_OK) { rc = cib_return_code; } if(rc == cib_ok || rc == cib_not_master || rc == cib_master_timeout) { crm_log_message(LOG_MSG, op_reply); } else { /* } else if(rc == cib_remote_timeout) { */ crm_err("Call failed: %s", cib_error2string(rc)); crm_log_message(LOG_WARNING, op_reply); } if(output_data == NULL) { /* do nothing more */ } else if(!(call_options & cib_discard_reply)) { *output_data = get_message_xml(op_reply, F_CIB_CALLDATA); if(*output_data == NULL) { crm_debug_3("No output in reply to \"%s\" command %d", op, cib->call_id - 1); } } crm_msg_del(op_reply); return rc; } gboolean cib_native_msgready(cib_t* cib) { cib_native_opaque_t *native = NULL; if (cib == NULL) { crm_err("No CIB!"); return FALSE; } native = cib->variant_opaque; if(native->command_channel != NULL) { /* drain the channel */ IPC_Channel *cmd_ch = native->command_channel; HA_Message *cmd_msg = NULL; while(cmd_ch->ch_status != IPC_DISCONNECT && cmd_ch->ops->is_message_pending(cmd_ch)) { /* we're not supposed to receive anything on * this channel */ crm_err("Message pending on command channel [%d]", cmd_ch->farside_pid); cmd_msg = msgfromIPC_noauth(cmd_ch); crm_log_message_adv(LOG_ERR, "cib:cmd", cmd_msg); crm_msg_del(cmd_msg); } } else { crm_err("No command channel"); } if(native->callback_channel == NULL) { crm_err("No callback channel"); return FALSE; } else if(native->callback_channel->ch_status == IPC_DISCONNECT) { crm_info("Lost connection to the CIB service [%d].", native->callback_channel->farside_pid); return FALSE; } else if(native->callback_channel->ops->is_message_pending( native->callback_channel)) { crm_debug_4("Message pending on command channel [%d]", native->callback_channel->farside_pid); return TRUE; } crm_debug_3("No message pending"); return FALSE; } int cib_native_rcvmsg(cib_t* cib, int blocking) { const char *type = NULL; struct ha_msg* msg = NULL; cib_native_opaque_t *native = NULL; if (cib == NULL) { crm_err("No CIB!"); return FALSE; } native = cib->variant_opaque; /* if it is not blocking mode and no message in the channel, return */ if (blocking == 0 && cib_native_msgready(cib) == FALSE) { crm_debug_3("No message ready and non-blocking..."); return 0; } else if (cib_native_msgready(cib) == FALSE) { crm_debug("Waiting for message from CIB service..."); if(native->callback_channel && native->callback_channel->ch_status != IPC_CONNECT) { return 0; } else if(native->command_channel && native->command_channel->ch_status != IPC_CONNECT){ return 0; } native->callback_channel->ops->waitin(native->callback_channel); } /* IPC_INTR is not a factor here */ msg = msgfromIPC_noauth(native->callback_channel); if (msg == NULL) { crm_warn("Received a NULL msg from CIB service."); return 0; } /* do callbacks */ type = cl_get_string(msg, F_TYPE); crm_debug_4("Activating %s callbacks...", type); if(safe_str_eq(type, T_CIB)) { cib_native_callback(cib, msg); } else if(safe_str_eq(type, T_CIB_NOTIFY)) { g_list_foreach(cib->notify_list, cib_native_notify, msg); } else { crm_err("Unknown message type: %s", type); } crm_msg_del(msg); return 1; } void cib_native_callback(cib_t *cib, struct ha_msg *msg) { int rc = 0; int call_id = 0; crm_data_t *output = NULL; cib_callback_client_t *blob = NULL; cib_callback_client_t local_blob; /* gcc4 had a point... make sure (at least) local_blob.callback * is initialized before use */ local_blob.callback = NULL; local_blob.user_data = NULL; local_blob.only_success = FALSE; ha_msg_value_int(msg, F_CIB_CALLID, &call_id); blob = g_hash_table_lookup( cib_op_callback_table, GINT_TO_POINTER(call_id)); if(blob != NULL) { crm_debug_3("Callback found for call %d", call_id); /* local_blob.callback = blob->callback; */ /* local_blob.user_data = blob->user_data; */ /* local_blob.only_success = blob->only_success; */ local_blob = *blob; blob = NULL; g_hash_table_remove( cib_op_callback_table, GINT_TO_POINTER(call_id)); } else { crm_debug_3("No callback found for call %d", call_id); local_blob.callback = NULL; } ha_msg_value_int(msg, F_CIB_RC, &rc); output = get_message_xml(msg, F_CIB_CALLDATA); if(local_blob.callback != NULL && (rc == cib_ok || local_blob.only_success == FALSE)) { local_blob.callback( msg, call_id, rc, output, local_blob.user_data); } else if(cib->op_callback == NULL && rc != cib_ok) { crm_warn("CIB command failed: %s", cib_error2string(rc)); crm_log_message_adv(LOG_DEBUG, "Failed CIB Update", msg); } if(cib->op_callback == NULL) { crm_debug_3("No OP callback set, ignoring reply"); } else { cib->op_callback(msg, call_id, rc, output); } free_xml(output); crm_debug_4("OP callback activated."); } void cib_native_notify(gpointer data, gpointer user_data) { struct ha_msg *msg = user_data; cib_notify_client_t *entry = data; const char *event = NULL; if(msg == NULL) { crm_warn("Skipping callback - NULL message"); return; } event = cl_get_string(msg, F_SUBTYPE); if(entry == NULL) { crm_warn("Skipping callback - NULL callback client"); return; } else if(entry->callback == NULL) { crm_warn("Skipping callback - NULL callback"); return; } else if(safe_str_neq(entry->event, event)) { crm_debug_4("Skipping callback - event mismatch %p/%s vs. %s", entry, entry->event, event); return; } crm_debug_4("Invoking callback for %p/%s event...", entry, event); entry->callback(event, msg); crm_debug_4("Callback invoked..."); } gboolean cib_native_dispatch(IPC_Channel *channel, gpointer user_data) { int lpc = 0; cib_t *cib = user_data; cib_native_opaque_t *native = NULL; crm_debug_3("Received callback"); if(user_data == NULL){ crm_err("user_data field must contain the CIB struct"); return FALSE; } native = cib->variant_opaque; while(cib_native_msgready(cib)) { lpc++; /* invoke the callbacks but dont block */ if(cib_native_rcvmsg(cib, 0) < 1) { break; } } crm_debug_3("%d CIB messages dispatched", lpc); if(native->callback_channel && native->callback_channel->ch_status != IPC_CONNECT) { crm_crit("Lost connection to the CIB service [%d/callback].", channel->farside_pid); G_main_del_IPC_Channel(native->callback_source); return FALSE; } else if(native->command_channel && native->command_channel->ch_status != IPC_CONNECT) { crm_crit("Lost connection to the CIB service [%d/command].", channel->farside_pid); return FALSE; } return TRUE; } int cib_native_set_connection_dnotify( cib_t *cib, void (*dnotify)(gpointer user_data)) { cib_native_opaque_t *native = NULL; if (cib == NULL) { crm_err("No CIB!"); return FALSE; } native = cib->variant_opaque; if(dnotify == NULL) { crm_warn("Setting dnotify back to default value"); set_IPC_Channel_dnotify(native->callback_source, default_ipc_connection_destroy); } else { crm_debug_3("Setting dnotify"); set_IPC_Channel_dnotify(native->callback_source, dnotify); } return cib_ok; } int cib_native_register_callback(cib_t* cib, const char *callback, int enabled) { HA_Message *notify_msg = ha_msg_new(3); cib_native_opaque_t *native = cib->variant_opaque; /* short term hack - should make this generic somehow */ ha_msg_add(notify_msg, F_CIB_OPERATION, T_CIB_NOTIFY); ha_msg_add(notify_msg, F_CIB_NOTIFY_TYPE, callback); ha_msg_add_int(notify_msg, F_CIB_NOTIFY_ACTIVATE, enabled); send_ipc_message(native->callback_channel, notify_msg); return cib_ok; } diff --git a/lib/crm/cib/cib_version.c b/lib/crm/cib/cib_version.c index 656dbe15bf..5cecc49195 100644 --- a/lib/crm/cib/cib_version.c +++ b/lib/crm/cib/cib_version.c @@ -1,135 +1,136 @@ -/* $Id: cib_version.c,v 1.3 2005/12/19 16:54:43 andrew Exp $ */ +/* $Id: cib_version.c,v 1.4 2006/03/18 17:23:48 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 const char * feature_sets[] = { "1.1", "1.2", }; typedef struct tag_set_s { int length; const char **tags; } tag_set_t; const char *feature_tags_12[] = { "master_slave", }; tag_set_t feature_tags[] = { { 0, NULL }, { 1, feature_tags_12 }, }; const char *feature_attrs_12[] = { "master_node_max", }; tag_set_t feature_attrs[] = { { 0, NULL }, { 1, feature_attrs_12 }, }; static int internal_update_feature_set(crm_data_t *xml_obj, int current) { int lpc = current; int lpc_nested = 0; const char *value = NULL; int num_sets = DIMOF(feature_sets); - CRM_DEV_ASSERT(compare_version(CIB_FEATURE_SET, - feature_sets[num_sets-1]) == 0); + CRM_CHECK(compare_version( + CIB_FEATURE_SET, feature_sets[num_sets-1]) == 0, + return num_sets-1); for(;lpc < num_sets; lpc++) { const char *tag = crm_element_name(xml_obj); crm_debug_3("Checking set %d with %d tags", lpc, feature_tags[lpc].length); lpc_nested = 0; for(; lpc_nested < feature_tags[lpc].length; lpc_nested++) { const char *name = feature_tags[lpc].tags[lpc_nested]; crm_debug_4("Checking %s vs. %s", tag, name); if(safe_str_eq(tag, name)) { crm_err("Found feature %s from set %s", tag, feature_sets[lpc]); current = lpc; break; } } if(current == lpc) { continue; } lpc_nested = 0; for(; lpc_nested < feature_attrs[lpc].length; lpc_nested++) { const char *name = feature_attrs[lpc].tags[lpc_nested]; crm_debug_4("Checking for %s", name); value = crm_element_value(xml_obj, name); if(value != NULL) { crm_err("Found feature %s from set %s", name, feature_sets[lpc]); current = lpc; break; } } } if(current == (num_sets -1)) { return current; } xml_child_iter(xml_obj, xml_child, current = internal_update_feature_set(xml_child,current); if(current == (num_sets -1)) { return current; } ); return current; } const char * feature_set(crm_data_t *xml_obj) { int set = internal_update_feature_set(xml_obj, 0); CRM_ASSERT(set < DIMOF(feature_sets)); return feature_sets[set]; } diff --git a/lib/crm/common/ipc.c b/lib/crm/common/ipc.c index 125a7cdac7..7432c3b9c6 100644 --- a/lib/crm/common/ipc.c +++ b/lib/crm/common/ipc.c @@ -1,443 +1,443 @@ -/* $Id: ipc.c,v 1.20 2006/02/19 20:02:19 andrew Exp $ */ +/* $Id: ipc.c,v 1.21 2006/03/18 17:23:48 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 #include #include gboolean send_ha_message(ll_cluster_t *hb_conn, HA_Message *msg, const char *node, gboolean force_ordered) { gboolean all_is_good = TRUE; if (msg == NULL) { crm_err("cant send NULL message"); all_is_good = FALSE; } else if(hb_conn == NULL) { crm_err("No heartbeat connection specified"); all_is_good = FALSE; } else if(hb_conn->llc_ops->chan_is_connected(hb_conn) == FALSE) { crm_err("Not connected to Heartbeat"); all_is_good = FALSE; } else if(get_stringlen(msg) >= MAXMSG) { crm_err("Message is too large to send"); all_is_good = FALSE; } else if(node != NULL) { if(hb_conn->llc_ops->send_ordered_nodemsg( hb_conn, msg, node) != HA_OK) { all_is_good = FALSE; crm_err("Send failed"); } else { crm_debug_2("Message sent..."); } } else if(force_ordered) { if(hb_conn->llc_ops->send_ordered_clustermsg(hb_conn, msg) != HA_OK) { all_is_good = FALSE; crm_err("Broadcast Send failed"); } else { crm_debug_2("Broadcast message sent..."); } } else { if(hb_conn->llc_ops->sendclustermsg(hb_conn, msg) != HA_OK) { all_is_good = FALSE; crm_err("Broadcast Send failed"); } else { crm_debug_2("Broadcast message sent..."); } } if(all_is_good == FALSE && hb_conn != NULL) { IPC_Channel *ipc = NULL; IPC_Queue *send_q = NULL; if(hb_conn->llc_ops->chan_is_connected(hb_conn) != HA_OK) { ipc = hb_conn->llc_ops->ipcchan(hb_conn); } if(ipc != NULL) { send_q = ipc->send_queue; } if(send_q != NULL) { - CRM_DEV_ASSERT(send_q->current_qlen < send_q->max_qlen); + CRM_CHECK(send_q->current_qlen < send_q->max_qlen, ;); } } crm_log_message_adv(all_is_good?LOG_MSG:LOG_WARNING,"HA[outbound]",msg); return all_is_good; } /* frees msg */ gboolean crm_send_ipc_message(IPC_Channel *ipc_client, HA_Message *msg, gboolean server) { gboolean all_is_good = TRUE; int fail_level = LOG_WARNING; if(ipc_client != NULL && ipc_client->conntype == IPC_CLIENT) { fail_level = LOG_ERR; } if (msg == NULL) { crm_err("cant send NULL message"); all_is_good = FALSE; } else if (ipc_client == NULL) { crm_err("cant send message without an IPC Channel"); all_is_good = FALSE; } else if(ipc_client->ops->get_chan_status(ipc_client) != IPC_CONNECT) { crm_log_maybe(fail_level, "IPC Channel to %d is not connected", (int)ipc_client->farside_pid); all_is_good = FALSE; } else if(get_stringlen(msg) >= MAXMSG) { crm_err("Message is to %d too large to send", (int)ipc_client->farside_pid); all_is_good = FALSE; } if(all_is_good && msg2ipcchan(msg, ipc_client) != HA_OK) { crm_log_maybe(fail_level, "Could not send IPC message to %d", (int)ipc_client->farside_pid); all_is_good = FALSE; if(ipc_client->ops->get_chan_status(ipc_client) != IPC_CONNECT) { crm_log_maybe(fail_level, "IPC Channel to %d is no longer connected", (int)ipc_client->farside_pid); } else if(server == FALSE) { - CRM_DEV_ASSERT(ipc_client->send_queue->current_qlen < ipc_client->send_queue->max_qlen); + CRM_CHECK(ipc_client->send_queue->current_qlen < ipc_client->send_queue->max_qlen, ;); } } crm_log_message_adv(all_is_good?LOG_MSG:LOG_WARNING,"IPC[outbound]",msg); crm_msg_del(msg); return all_is_good; } void default_ipc_connection_destroy(gpointer user_data) { return; } int init_server_ipc_comms( char *channel_name, gboolean (*channel_client_connect)(IPC_Channel *newclient,gpointer user_data), void (*channel_connection_destroy)(gpointer user_data)) { /* the clients wait channel is the other source of events. * This source delivers the clients connection events. * listen to this source at a relatively lower priority. */ char commpath[SOCKET_LEN]; IPC_WaitConnection *wait_ch; sprintf(commpath, CRM_SOCK_DIR "/%s", channel_name); wait_ch = wait_channel_init(commpath); if (wait_ch == NULL) { return 1; } G_main_add_IPC_WaitConnection( G_PRIORITY_LOW, wait_ch, NULL, FALSE, channel_client_connect, channel_name, channel_connection_destroy); crm_debug_3("Listening on: %s", commpath); return 0; } GCHSource* init_client_ipc_comms(const char *channel_name, gboolean (*dispatch)( IPC_Channel* source_data, gpointer user_data), void *client_data, IPC_Channel **ch) { IPC_Channel *a_ch = NULL; GCHSource *the_source = NULL; void *callback_data = client_data; a_ch = init_client_ipc_comms_nodispatch(channel_name); if(ch != NULL) { *ch = a_ch; if(callback_data == NULL) { callback_data = a_ch; } } if(a_ch == NULL) { crm_warn("Setup of client connection failed," " not adding channel to mainloop"); return NULL; } if(dispatch == NULL) { crm_warn("No dispatch method specified..." "maybe you meant init_client_ipc_comms_nodispatch()?"); } else { crm_debug_3("Adding dispatch method to channel"); the_source = G_main_add_IPC_Channel( G_PRIORITY_HIGH, a_ch, FALSE, dispatch, callback_data, default_ipc_connection_destroy); } return the_source; } IPC_Channel * init_client_ipc_comms_nodispatch(const char *channel_name) { IPC_Channel *ch; GHashTable *attrs; static char path[] = IPC_PATH_ATTR; char *commpath = NULL; int local_socket_len = 2; /* 2 = '/' + '\0' */ local_socket_len += strlen(channel_name); local_socket_len += strlen(CRM_SOCK_DIR); crm_malloc0(commpath, sizeof(char)*local_socket_len); if(commpath != NULL) { sprintf(commpath, CRM_SOCK_DIR "/%s", channel_name); commpath[local_socket_len - 1] = '\0'; crm_debug_3("Attempting to talk on: %s", commpath); } attrs = g_hash_table_new(g_str_hash,g_str_equal); g_hash_table_insert(attrs, path, commpath); ch = ipc_channel_constructor(IPC_ANYTYPE, attrs); g_hash_table_destroy(attrs); if (ch == NULL) { crm_err("Could not access channel on: %s", commpath); return NULL; } else if (ch->ops->initiate_connection(ch) != IPC_OK) { crm_debug("Could not init comms on: %s", commpath); ch->ops->destroy(ch); return NULL; } ch->ops->set_recv_qlen(ch, 100); ch->ops->set_send_qlen(ch, 100); /* ch->should_send_block = TRUE; */ crm_debug_3("Processing of %s complete", commpath); return ch; } IPC_WaitConnection * wait_channel_init(char daemonsocket[]) { IPC_WaitConnection *wait_ch; mode_t mask; char path[] = IPC_PATH_ATTR; GHashTable * attrs; attrs = g_hash_table_new(g_str_hash,g_str_equal); g_hash_table_insert(attrs, path, daemonsocket); mask = umask(0); wait_ch = ipc_wait_conn_constructor(IPC_ANYTYPE, attrs); if (wait_ch == NULL) { cl_perror("Can't create wait channel of type %s", IPC_ANYTYPE); exit(1); } mask = umask(mask); g_hash_table_destroy(attrs); return wait_ch; } longclock_t ipc_call_start = 0; longclock_t ipc_call_stop = 0; longclock_t ipc_call_diff = 0; gboolean subsystem_msg_dispatch(IPC_Channel *sender, void *user_data) { int lpc = 0; int rc = IPC_OK; IPC_Message *msg = NULL; ha_msg_input_t *new_input = NULL; gboolean all_is_well = TRUE; const char *sys_to; const char *task; while(IPC_ISRCONN(sender)) { gboolean process = FALSE; if(sender->ops->is_message_pending(sender) == 0) { break; } rc = sender->ops->recv(sender, &msg); if (rc != IPC_OK) { crm_err("Receive failure from %d: %d", sender->farside_pid, rc); return !all_is_well; } else if (msg == NULL) { crm_err("No message from %d this time", sender->farside_pid); continue; } lpc++; new_input = new_ipc_msg_input(msg); msg->msg_done(msg); crm_log_message(LOG_MSG, new_input->msg); sys_to = cl_get_string(new_input->msg, F_CRM_SYS_TO); task = cl_get_string(new_input->msg, F_CRM_TASK); if(safe_str_eq(task, CRM_OP_HELLO)) { process = TRUE; } else if(sys_to == NULL) { crm_err("Value of %s was NULL!!", F_CRM_SYS_TO); } else if(task == NULL) { crm_err("Value of %s was NULL!!", F_CRM_TASK); } else { process = TRUE; } if(process){ gboolean (*process_function) (HA_Message *msg, crm_data_t *data, IPC_Channel *sender) = NULL; process_function = user_data; #ifdef MSG_LOG crm_log_message_adv( LOG_MSG, __FUNCTION__, new_input->msg); #endif if(ipc_call_diff_max_ms > 0) { ipc_call_start = time_longclock(); } if(FALSE == process_function( new_input->msg, new_input->xml, sender)) { crm_warn("Received a message destined for %s" " by mistake", sys_to); } if(ipc_call_diff_max_ms > 0) { unsigned int ipc_call_diff_ms = 0; ipc_call_stop = time_longclock(); ipc_call_diff = sub_longclock( ipc_call_stop, ipc_call_start); ipc_call_diff_ms = longclockto_ms( ipc_call_diff); if(ipc_call_diff_ms > ipc_call_diff_max_ms) { crm_err("%s took %dms to complete", sys_to, ipc_call_diff_ms); } } } else { #ifdef MSG_LOG crm_log_message_adv( LOG_ERR, NULL, new_input->msg); #endif } delete_ha_msg_input(new_input); msg = NULL; if(sender->ch_status == IPC_CONNECT) { break; } } /* clean up after a break */ if(msg != NULL) { msg->msg_done(msg); } crm_debug_2("Processed %d messages", lpc); if (sender->ch_status != IPC_CONNECT) { crm_err("The server %d has left us: Shutting down...NOW", sender->farside_pid); exit(1); /* shutdown properly later */ return !all_is_well; } return all_is_well; } gboolean is_ipc_empty(IPC_Channel *ch) { if(ch == NULL) { return TRUE; } else if(ch->send_queue->current_qlen == 0 && ch->recv_queue->current_qlen == 0) { return TRUE; } return FALSE; } diff --git a/lib/crm/common/iso8601.c b/lib/crm/common/iso8601.c index 144887c976..35add5578a 100644 --- a/lib/crm/common/iso8601.c +++ b/lib/crm/common/iso8601.c @@ -1,1245 +1,1245 @@ -/* $Id: iso8601.c,v 1.12 2005/11/09 16:00:16 davidlee Exp $ */ +/* $Id: iso8601.c,v 1.13 2006/03/18 17:23:48 andrew Exp $ */ /* * Copyright (C) 2005 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 */ /* * Primary reference: * http://en.wikipedia.org/wiki/ISO_8601 (as at 2005-08-01) * * Secondary references: * http://hydracen.com/dx/iso8601.htm * http://www.personal.ecu.edu/mccartyr/ISOwdALG.txt * http://www.personal.ecu.edu/mccartyr/isowdcal.html * http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm * */ #include #include #include #include #include gboolean gregorian_to_ordinal(ha_time_t *a_date); gboolean ordinal_to_gregorian(ha_time_t *a_date); gboolean ordinal_to_weekdays(ha_time_t *a_date); void normalize_time(ha_time_t *a_time); /* * Andrew's code was originally written for OSes whose "struct tm" contains: * long tm_gmtoff; :: Seconds east of UTC * const char *tm_zone; :: Timezone abbreviation * Some OSes lack these, instead having: * time_t (or long) timezone; :: "difference between UTC and local standard time" * char *tzname[2] = { "...", "..." }; * I (David Lee) confess to not understanding the details. So my attempted * generalisations for where their use is necessary may be flawed. * * 1. Does "difference between ..." subtract the same or opposite way? * 2. Should it use "altzone" instead of "timezone"? * 3. Should it use tzname[0] or tzname[1]? Interaction with timezone/altzone? */ #if defined(HAVE_TM_GMTOFF) #define GMTOFF(tm) ((tm)->tm_gmtoff) #else /* Note: extern variable; macro argument not actually used. */ #define GMTOFF(tm) (timezone) #endif void log_date(int log_level, const char *prefix, ha_time_t *date_time, int flags) { char *date_s = NULL; char *time_s = NULL; char *offset_s = NULL; ha_time_t *dt = NULL; if(flags & ha_log_local) { crm_debug_6("Local version"); dt = date_time; } else { dt = date_time->normalized; } - CRM_DEV_ASSERT(dt != NULL); if(crm_assert_failed) { return; } + CRM_CHECK(dt != NULL, return); if(flags & ha_log_date) { crm_malloc0(date_s, sizeof(char)*(32)); if(date_s == NULL) { } else if(flags & ha_date_weeks) { snprintf(date_s, 31, "%d-W%.2d-%d", dt->weekyears, dt->weeks, dt->weekdays); } else if(flags & ha_date_ordinal) { snprintf(date_s, 31, "%d-%.3d",dt->years, dt->yeardays); } else { snprintf(date_s, 31, "%.4d-%.2d-%.2d", dt->years, dt->months, dt->days); } } if(flags & ha_log_time) { int offset = 0; crm_malloc0(time_s, sizeof(char)*(32)); if(time_s == NULL) { return; } snprintf(time_s, 31, "%.2d:%.2d:%.2d", dt->hours, dt->minutes, dt->seconds); if(dt->offset != NULL) { offset =(dt->offset->hours * 100) + dt->offset->minutes; } crm_malloc0(offset_s, sizeof(char)*(32)); if((flags & ha_log_local) == 0 || offset == 0) { snprintf(offset_s, 31, "Z"); } else { int hr = dt->offset->hours; int mins = dt->offset->minutes; if(hr < 0) { hr = 0 - hr; } if(mins < 0) { mins = 0 - mins; } snprintf(offset_s, 31, " %s%.2d:%.2d", offset>0?"+":"-", hr, mins); } } crm_log_maybe(log_level, "%s%s%s%s%s%s", prefix?prefix:"", prefix?": ":"", date_s?date_s:"", (date_s!=NULL&&time_s!=NULL)?" ":"", time_s?time_s:"", offset_s?offset_s:""); crm_free(date_s); crm_free(time_s); crm_free(offset_s); } void log_time_period(int log_level, ha_time_period_t *dtp, int flags) { log_date(log_level, "Period start:", dtp->start, flags); log_date(log_level, "Period end:", dtp->end, flags); } ha_time_t* parse_time_offset(char **offset_str) { ha_time_t *new_time = NULL; crm_malloc0(new_time, sizeof(ha_time_t)); crm_malloc0(new_time->has, sizeof(ha_has_time_t)); if((*offset_str)[0] == 'Z') { } else if((*offset_str)[0] == '+' || (*offset_str)[0] == '-' || isdigit((int) (*offset_str)[0])) { gboolean negate = FALSE; if((*offset_str)[0] == '-') { negate = TRUE; (*offset_str)++; } parse_time(offset_str, new_time, FALSE); if(negate) { new_time->hours = 0 - new_time->hours; new_time->minutes = 0 - new_time->minutes; new_time->seconds = 0 - new_time->seconds; } } else { #if defined(HAVE_TM_GMTOFF) time_t now = time(NULL); struct tm *now_tm = localtime(&now); #endif int h_offset = GMTOFF(now_tm) / (3600); int m_offset = (GMTOFF(now_tm) - (3600 * h_offset)) / (60); if(h_offset < 0 && m_offset < 0) { m_offset = 0 - m_offset; } new_time->hours = h_offset; new_time->minutes = m_offset; new_time->has->hours = TRUE; new_time->has->minutes = TRUE; } return new_time; } ha_time_t* parse_time(char **time_str, ha_time_t *a_time, gboolean with_offset) { ha_time_t *new_time = a_time; tzset(); if(a_time == NULL) { new_time = new_ha_date(FALSE); } - CRM_DEV_ASSERT(new_time != NULL); - CRM_DEV_ASSERT(new_time->has != NULL); + CRM_CHECK(new_time != NULL, return NULL); + CRM_CHECK(new_time->has != NULL, return NULL); crm_debug_4("Get hours..."); if(parse_int(time_str, 2, 24, &new_time->hours)) { new_time->has->hours = TRUE; } crm_debug_4("Get minutes..."); if(parse_int(time_str, 2, 60, &new_time->minutes)) { new_time->has->minutes = TRUE; } crm_debug_4("Get seconds..."); if(parse_int(time_str, 2, 60, &new_time->seconds)){ new_time->has->seconds = TRUE; } if(with_offset) { crm_debug_4("Get offset..."); while(isspace((int) (*time_str)[0])) { (*time_str)++; } new_time->offset = parse_time_offset(time_str); normalize_time(new_time); } return new_time; } void normalize_time(ha_time_t *a_time) { - CRM_DEV_ASSERT(a_time != NULL); - CRM_DEV_ASSERT(a_time->has != NULL); + CRM_CHECK(a_time != NULL, return); + CRM_CHECK(a_time->has != NULL, return); if(a_time->normalized == NULL) { crm_malloc0(a_time->normalized, sizeof(ha_time_t)); } if(a_time->normalized->has == NULL) { crm_malloc0(a_time->normalized->has, sizeof(ha_has_time_t)); } ha_set_time(a_time->normalized, a_time, FALSE); if(a_time->offset != NULL) { if(a_time->offset->has->hours) { sub_hours(a_time->normalized, a_time->offset->hours); } if(a_time->offset->has->minutes) { sub_minutes(a_time->normalized,a_time->offset->minutes); } if(a_time->offset->has->seconds) { sub_seconds(a_time->normalized,a_time->offset->seconds); } } - CRM_DEV_ASSERT(is_date_sane(a_time)); + CRM_CHECK(is_date_sane(a_time), return); } ha_time_t * parse_date(char **date_str) { gboolean is_done = FALSE; gboolean converted = FALSE; ha_time_t *new_time = NULL; crm_malloc0(new_time, sizeof(ha_time_t)); crm_malloc0(new_time->has, sizeof(ha_has_time_t)); - CRM_DEV_ASSERT(date_str != NULL); - CRM_DEV_ASSERT(strlen(*date_str) > 0); + CRM_CHECK(date_str != NULL, return NULL); + CRM_CHECK(strlen(*date_str) > 0, return NULL); while(is_done == FALSE) { char ch = (*date_str)[0]; crm_debug_5("Switching on ch=%c (len=%d)", ch, (int)strlen(*date_str)); if(ch == 0) { /* all done */ is_done = TRUE; break; } else if(ch == '/') { /* all done - interval marker */ is_done = TRUE; break; } else if(ch == 'W') { - CRM_DEV_ASSERT(new_time->has->weeks == FALSE); + CRM_CHECK(new_time->has->weeks == FALSE, ;); (*date_str)++; if(parse_int(date_str, 2, 53, &new_time->weeks)){ new_time->has->weeks = TRUE; new_time->weekyears = new_time->years; new_time->has->weekyears = new_time->has->years; } if((*date_str)[0] == '-') { (*date_str)++; if(parse_int(date_str, 1, 7, &new_time->weekdays)) { new_time->has->weekdays = TRUE; } } if(new_time->weekdays == 0 || new_time->has->weekdays == FALSE) { new_time->weekdays = 1; new_time->has->weekdays = TRUE; } } else if(ch == '-') { (*date_str)++; if(check_for_ordinal(*date_str)) { if(parse_int(date_str, 3, 366, &new_time->yeardays)) { new_time->has->yeardays = TRUE; } } } else if(ch == 'O') { /* ordinal date */ (*date_str)++; if(parse_int(date_str, 3, 366, &new_time->yeardays)){ new_time->has->yeardays = TRUE; } } else if(ch == 'T' || ch == ' ') { if(new_time->has->yeardays) { converted = convert_from_ordinal(new_time); } else if(new_time->has->weekdays) { converted = convert_from_weekdays(new_time); } else { converted = convert_from_gregorian(new_time); } (*date_str)++; parse_time(date_str, new_time, TRUE); is_done = TRUE; } else if(isdigit((int) ch)) { if(new_time->has->years == FALSE && parse_int(date_str, 4, 9999, &new_time->years)) { new_time->has->years = TRUE; } else if(check_for_ordinal(*date_str) && parse_int( date_str, 3, is_leap_year(new_time->years)?366:365, &new_time->yeardays)) { new_time->has->yeardays = TRUE; } else if(new_time->has->months == FALSE && parse_int(date_str, 2, 12, &new_time->months)) { new_time->has->months = TRUE; } else if(new_time->has->days == FALSE) { if(parse_int(date_str, 2, days_per_month(new_time->months, new_time->years), &new_time->days)) { new_time->has->days = TRUE; } } } else { crm_err("Unexpected characters at: %s", *date_str); is_done = TRUE; break; } } if(converted) { } else if(new_time->has->yeardays) { convert_from_ordinal(new_time); } else if(new_time->has->weekdays) { convert_from_weekdays(new_time); } else { convert_from_gregorian(new_time); } normalize_time(new_time); log_date(LOG_DEBUG_3, "Unpacked", new_time, ha_log_date|ha_log_time); - CRM_DEV_ASSERT(is_date_sane(new_time)); + CRM_CHECK(is_date_sane(new_time), return NULL); return new_time; } ha_time_t* parse_time_duration(char **interval_str) { gboolean is_time = FALSE; ha_time_t *diff = NULL; crm_malloc0(diff, sizeof(ha_time_t)); crm_malloc0(diff->has, sizeof(ha_has_time_t)); - CRM_DEV_ASSERT(interval_str != NULL); - CRM_DEV_ASSERT(strlen(*interval_str) > 0); + CRM_CHECK(interval_str != NULL, return NULL); + CRM_CHECK(strlen(*interval_str) > 0, return NULL); - CRM_DEV_ASSERT((*interval_str)[0] == 'P'); + CRM_CHECK((*interval_str)[0] == 'P', return NULL); (*interval_str)++; while(isspace((int) (*interval_str)[0]) == FALSE) { int an_int = 0; char ch = 0; if((*interval_str)[0] == 'T') { is_time = TRUE; (*interval_str)++; } if(parse_int(interval_str, 10, 0, &an_int) == FALSE) { break; } ch = (*interval_str)[0]; (*interval_str)++; crm_debug_4("%c=%d", ch, an_int); switch(ch) { case 0: return diff; break; case 'Y': diff->years = an_int; diff->has->years = TRUE; break; case 'M': if(is_time) { diff->minutes = an_int; diff->has->minutes = TRUE; } else { diff->months = an_int; diff->has->months = TRUE; } break; case 'W': diff->weeks = an_int; diff->has->weeks = TRUE; break; case 'D': diff->days = an_int; diff->has->days = TRUE; break; case 'H': diff->hours = an_int; diff->has->hours = TRUE; break; case 'S': diff->seconds = an_int; diff->has->seconds = TRUE; break; default: break; } } return diff; } ha_time_period_t* parse_time_period(char **period_str) { gboolean invalid = FALSE; const char *original = *period_str; ha_time_period_t *period = NULL; crm_malloc0(period, sizeof(ha_time_period_t)); - CRM_DEV_ASSERT(period_str != NULL); - CRM_DEV_ASSERT(strlen(*period_str) > 0); + CRM_CHECK(period_str != NULL, return NULL); + CRM_CHECK(strlen(*period_str) > 0, return NULL); tzset(); if((*period_str)[0] == 'P') { period->diff = parse_time_duration(period_str); } else { period->start = parse_date(period_str); } if((*period_str)[0] != 0) { - CRM_DEV_ASSERT((*period_str)[0] == '/'); + CRM_CHECK((*period_str)[0] == '/', return NULL); (*period_str)++; if((*period_str)[0] == 'P') { period->diff = parse_time_duration(period_str); } else { period->end = parse_date(period_str); } } else if(period->diff != NULL) { /* just aduration starting from now */ time_t now = time(NULL); crm_malloc0(period->start, sizeof(ha_time_t)); crm_malloc0(period->start->has, sizeof(ha_has_time_t)); crm_malloc0(period->start->offset, sizeof(ha_time_t)); crm_malloc0(period->start->offset->has, sizeof(ha_has_time_t)); ha_set_timet_time(period->start, &now); normalize_time(period->start); } else { - CRM_DEV_ASSERT((*period_str)[0] == '/'); + CRM_CHECK((*period_str)[0] == '/', return NULL); return NULL; } /* sanity checks */ if(period->start == NULL && period->end == NULL) { crm_err("Invalid time period: %s", original); invalid = TRUE; } else if(period->start == NULL && period->diff == NULL) { crm_err("Invalid time period: %s", original); invalid = TRUE; } else if(period->end == NULL && period->diff == NULL) { crm_err("Invalid time period: %s", original); invalid = TRUE; } if(invalid) { crm_free(period->start); crm_free(period->end); crm_free(period->diff); crm_free(period); return NULL; } if(period->end == NULL && period->diff == NULL) { } if(period->start == NULL) { period->start = subtract_time(period->end, period->diff); normalize_time(period->start); } else if(period->end == NULL) { period->end = add_time(period->start, period->diff); normalize_time(period->end); } is_date_sane(period->start); is_date_sane(period->end); return period; } int month2days[13] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; /* http://www.personal.ecu.edu/mccartyr/ISOwdALG.txt */ int january1(int year) { int YY = (year - 1) % 100; int C = (year - 1) - YY; int G = YY + YY/4; int jan1 = 1 + (((((C / 100) % 4) * 5) + G) % 7); crm_debug_6("YY=%d, C=%d, G=%d", YY, C, G); crm_debug_5("January 1 %.4d: %d", year, jan1); return jan1; } int weeks_in_year(int year) { int weeks = 52; int jan1 = january1(year); /* if jan1 == thursday */ if(jan1 == 4) { weeks++; } else { jan1 = january1(year+1); /* if dec31 == thursday aka. jan1 of next year is a friday */ if(jan1 == 5) { weeks++; } } return weeks; } gboolean convert_from_gregorian(ha_time_t *a_date) { - CRM_DEV_ASSERT(gregorian_to_ordinal(a_date)); - CRM_DEV_ASSERT(ordinal_to_weekdays(a_date)); + CRM_CHECK(gregorian_to_ordinal(a_date), return FALSE); + CRM_CHECK(ordinal_to_weekdays(a_date), return FALSE); return TRUE; } gboolean gregorian_to_ordinal(ha_time_t *a_date) { - CRM_DEV_ASSERT(a_date->has->years); - CRM_DEV_ASSERT(a_date->has->months); - CRM_DEV_ASSERT(a_date->has->days); + CRM_CHECK(a_date->has->years, return FALSE); + CRM_CHECK(a_date->has->months, return FALSE); + CRM_CHECK(a_date->has->days, return FALSE); - CRM_DEV_ASSERT(a_date->months > 0); - CRM_DEV_ASSERT(a_date->days > 0); + CRM_CHECK(a_date->months > 0, return FALSE); + CRM_CHECK(a_date->days > 0, return FALSE); a_date->yeardays = month2days[a_date->months-1]; a_date->yeardays += a_date->days; a_date->has->yeardays = TRUE; if(is_leap_year(a_date->years) && a_date->months > 2) { (a_date->yeardays)++; } crm_debug_4("Converted %.4d-%.2d-%.2d to %.4d-%.3d", a_date->years, a_date->months, a_date->days, a_date->years, a_date->yeardays); return TRUE; } gboolean convert_from_ordinal(ha_time_t *a_date) { - CRM_DEV_ASSERT(ordinal_to_gregorian(a_date)); - CRM_DEV_ASSERT(ordinal_to_weekdays(a_date)); + CRM_CHECK(ordinal_to_gregorian(a_date), return FALSE); + CRM_CHECK(ordinal_to_weekdays(a_date), return FALSE); return TRUE; } gboolean ordinal_to_gregorian(ha_time_t *a_date) { - CRM_DEV_ASSERT(a_date->has->years); - CRM_DEV_ASSERT(a_date->has->yeardays); + CRM_CHECK(a_date->has->years, return FALSE); + CRM_CHECK(a_date->has->yeardays, return FALSE); - CRM_DEV_ASSERT(a_date->yeardays > 0); + CRM_CHECK(a_date->yeardays > 0, return FALSE); a_date->days = a_date->yeardays; a_date->months = 11; if(is_leap_year(a_date->years) && a_date->yeardays > 366) { crm_err("Year %.4d only has 366 days (supplied %.3d)", a_date->years, a_date->yeardays); a_date->yeardays = 366; } else if(!is_leap_year(a_date->years) && a_date->yeardays > 365) { crm_err("Year %.4d only has 365 days (supplied %.3d)", a_date->years, a_date->yeardays); a_date->yeardays = 365; } while(a_date->months > 0 && a_date->yeardays <= month2days[a_date->months]) { crm_debug_6("month %d: %d vs. %d", a_date->months, a_date->yeardays, month2days[a_date->months]); (a_date->months)--; } a_date->days -= month2days[a_date->months]; (a_date->months)++; - CRM_DEV_ASSERT(a_date->months > 0); + CRM_CHECK(a_date->months > 0, return FALSE); if(is_leap_year(a_date->years) && a_date->months > 2) { (a_date->days)--; } if(a_date->days == 0) { /* annoying underflow */ a_date->days = days_per_month(a_date->months, a_date->years); (a_date->months)--; } a_date->has->days = TRUE; a_date->has->months = TRUE; a_date->has->years = TRUE; crm_debug_4("Converted %.4d-%.3d to %.4d-%.2d-%.2d", a_date->years, a_date->yeardays, a_date->years, a_date->months, a_date->days); return TRUE; } gboolean ordinal_to_weekdays(ha_time_t *a_date) { int year_num = 0; int jan1 = january1(a_date->years); int h = -1; - CRM_DEV_ASSERT(a_date->has->years); - CRM_DEV_ASSERT(a_date->has->yeardays); - CRM_DEV_ASSERT(a_date->yeardays > 0); + CRM_CHECK(a_date->has->years, return FALSE); + CRM_CHECK(a_date->has->yeardays, return FALSE); + CRM_CHECK(a_date->yeardays > 0, return FALSE); h = a_date->yeardays + jan1 - 1; a_date->weekdays = 1 + ((h-1) % 7); a_date->has->weekdays = TRUE; if(a_date->yeardays <= (8-jan1) && jan1 > 4) { year_num = a_date->years - 1; a_date->weeks = weeks_in_year(year_num); a_date->has->weeks = TRUE; } else { year_num = a_date->years; } if(year_num == a_date->years) { int i = 365; if(is_leap_year(year_num)) { i = 366; } if( (i - a_date->yeardays) < (4 - a_date->weekdays) ) { year_num = a_date->years + 1; a_date->weeks = 1; a_date->has->weeks = TRUE; } } if(year_num == a_date->years) { int j = a_date->yeardays + (7-a_date->weekdays) + (jan1 - 1); a_date->weeks = j / 7; a_date->has->weeks = TRUE; if(jan1 > 4) { a_date->weeks -= 1; } } a_date->weekyears = year_num; a_date->has->weekyears = TRUE; crm_debug_4("Converted %.4d-%.3d to %.4dW%.2d-%d", a_date->years, a_date->yeardays, a_date->weekyears, a_date->weeks, a_date->weekdays); return TRUE; } gboolean convert_from_weekdays(ha_time_t *a_date) { gboolean conversion = FALSE; int jan1 = january1(a_date->weekyears); - CRM_DEV_ASSERT(a_date->has->weekyears); - CRM_DEV_ASSERT(a_date->has->weeks); - CRM_DEV_ASSERT(a_date->has->weekdays); + CRM_CHECK(a_date->has->weekyears, return FALSE); + CRM_CHECK(a_date->has->weeks, return FALSE); + CRM_CHECK(a_date->has->weekdays, return FALSE); - CRM_DEV_ASSERT(a_date->weeks > 0); - CRM_DEV_ASSERT(a_date->weekdays > 0); - CRM_DEV_ASSERT(a_date->weekdays < 8); + CRM_CHECK(a_date->weeks > 0, return FALSE); + CRM_CHECK(a_date->weekdays > 0, return FALSE); + CRM_CHECK(a_date->weekdays < 8, return FALSE); a_date->has->years = TRUE; a_date->years = a_date->weekyears; a_date->has->yeardays = TRUE; a_date->yeardays = (7 * (a_date->weeks-1)); /* break up the addition to make sure overflows are correctly handled */ if(a_date->yeardays == 0) { a_date->yeardays = a_date->weekdays; } else { add_yeardays(a_date, a_date->weekdays); } crm_debug_5("Pre-conversion: %dW%d-%d to %.4d-%.3d", a_date->weekyears, a_date->weeks, a_date->weekdays, a_date->years, a_date->yeardays); conversion = ordinal_to_gregorian(a_date); if(conversion) { if(jan1 < 4) { sub_days(a_date, jan1-1); } else if(jan1 > 4) { add_days(a_date, jan1-4); } } return conversion; } void ha_set_time(ha_time_t *lhs, ha_time_t *rhs, gboolean offset) { crm_debug_6("lhs=%p, rhs=%p, offset=%d", lhs, rhs, offset); - CRM_DEV_ASSERT(lhs != NULL && rhs != NULL); - CRM_DEV_ASSERT(lhs->has != NULL && rhs->has != NULL); + CRM_CHECK(lhs != NULL && rhs != NULL, return); + CRM_CHECK(lhs->has != NULL && rhs->has != NULL, return); lhs->years = rhs->years; lhs->has->years = rhs->has->years; lhs->weekyears = rhs->weekyears; lhs->has->weekyears = rhs->has->weekyears; lhs->months = rhs->months; lhs->has->months = rhs->has->months; lhs->weeks = rhs->weeks; lhs->has->weeks = rhs->has->weeks; lhs->days = rhs->days; lhs->has->days = rhs->has->days; lhs->weekdays = rhs->weekdays; lhs->has->weekdays = rhs->has->weekdays; lhs->yeardays = rhs->yeardays; lhs->has->yeardays = rhs->has->yeardays; lhs->hours = rhs->hours; lhs->has->hours = rhs->has->hours; lhs->minutes = rhs->minutes; lhs->has->minutes = rhs->has->minutes; lhs->seconds = rhs->seconds; lhs->has->seconds = rhs->has->seconds; if(lhs->offset) { reset_time(lhs->offset); } if(offset && rhs->offset) { ha_set_time(lhs->offset, rhs->offset, FALSE); } } void ha_set_tm_time(ha_time_t *lhs, struct tm *rhs) { int wday = rhs->tm_wday; int h_offset = 0; int m_offset = 0; if(rhs->tm_year > 0) { /* years since 1900 */ lhs->years = 1900 + rhs->tm_year; lhs->has->years = TRUE; } if(rhs->tm_yday > 0) { /* days since January 1 [0-365] */ lhs->yeardays = 1 + rhs->tm_yday; lhs->has->yeardays =TRUE; } if(rhs->tm_hour >= 0) { lhs->hours = rhs->tm_hour; lhs->has->hours =TRUE; } if(rhs->tm_min >= 0) { lhs->minutes = rhs->tm_min; lhs->has->minutes =TRUE; } if(rhs->tm_sec >= 0) { lhs->seconds = rhs->tm_sec; lhs->has->seconds =TRUE; } convert_from_ordinal(lhs); /* months since January [0-11] */ - CRM_DEV_ASSERT(rhs->tm_mon < 0 || lhs->months == (1 + rhs->tm_mon)); + CRM_CHECK(rhs->tm_mon < 0 || lhs->months == (1 + rhs->tm_mon), return); /* day of the month [1-31] */ - CRM_DEV_ASSERT(rhs->tm_mday < 0 || lhs->days == rhs->tm_mday); + CRM_CHECK(rhs->tm_mday < 0 || lhs->days == rhs->tm_mday, return); /* days since Sunday [0-6] */ if(wday == 0) { wday= 7; } - CRM_DEV_ASSERT(rhs->tm_wday < 0 || lhs->weekdays == wday); - CRM_DEV_ASSERT(lhs->offset != NULL); - CRM_DEV_ASSERT(lhs->offset->has != NULL); + CRM_CHECK(rhs->tm_wday < 0 || lhs->weekdays == wday, return); + CRM_CHECK(lhs->offset != NULL, return); + CRM_CHECK(lhs->offset->has != NULL, return); /* tm_gmtoff == offset from UTC in seconds */ h_offset = GMTOFF(rhs) / (3600); m_offset = (GMTOFF(rhs) - (3600 * h_offset)) / (60); crm_debug_6("Offset (s): %ld, offset (hh:mm): %.2d:%.2d", GMTOFF(rhs), h_offset, m_offset); lhs->offset->hours = h_offset; lhs->offset->has->hours = TRUE; lhs->offset->minutes = m_offset; lhs->offset->has->minutes = TRUE; normalize_time(lhs); } void ha_set_timet_time(ha_time_t *lhs, time_t *rhs) { ha_set_tm_time(lhs, localtime(rhs)); } ha_time_t * add_time(ha_time_t *lhs, ha_time_t *rhs) { ha_time_t *answer = NULL; - CRM_DEV_ASSERT(lhs != NULL && rhs != NULL); + CRM_CHECK(lhs != NULL && rhs != NULL, return NULL); answer = new_ha_date(FALSE); ha_set_time(answer, lhs, TRUE); normalize_time(lhs); normalize_time(answer); if(rhs->has->years) { add_years(answer, rhs->years); } if(rhs->has->months) { add_months(answer, rhs->months); } if(rhs->has->weeks) { add_weeks(answer, rhs->weeks); } if(rhs->has->days) { add_days(answer, rhs->days); } add_hours(answer, rhs->hours); add_minutes(answer, rhs->minutes); add_seconds(answer, rhs->seconds); return answer; } ha_time_t * subtract_time(ha_time_t *lhs, ha_time_t *rhs) { ha_time_t *answer = NULL; - CRM_DEV_ASSERT(lhs != NULL && rhs != NULL); + CRM_CHECK(lhs != NULL && rhs != NULL, return NULL); answer = new_ha_date(FALSE); ha_set_time(answer, lhs, TRUE); normalize_time(lhs); normalize_time(rhs); normalize_time(answer); sub_years(answer, rhs->years); sub_months(answer, rhs->months); sub_weeks(answer, rhs->weeks); sub_days(answer, rhs->days); sub_hours(answer, rhs->hours); sub_minutes(answer, rhs->minutes); sub_seconds(answer, rhs->seconds); return answer; } /* ha_time_interval_t* */ /* parse_time_interval(char **interval_str) */ /* { */ /* return NULL; */ /* } */ int month_days[14] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 29 }; int days_per_month(int month, int year) { if(month == 2 && is_leap_year(year)) { month = 13; } return month_days[month]; } gboolean is_leap_year(int year) { gboolean is_leap = FALSE; if(year % 4 == 0) { is_leap = TRUE; } if(year % 100 == 0 && year % 400 != 0 ) { is_leap = FALSE; } return is_leap; } gboolean parse_int(char **str, int field_width, int uppper_bound, int *result) { int lpc = 0; int intermediate = 0; gboolean fraction = FALSE; gboolean negate = FALSE; - CRM_DEV_ASSERT(str != NULL); - CRM_DEV_ASSERT(*str != NULL); - CRM_DEV_ASSERT(result != NULL); + CRM_CHECK(str != NULL, return FALSE); + CRM_CHECK(*str != NULL, return FALSE); + CRM_CHECK(result != NULL, return FALSE); *result = 0; if(strlen(*str) <= 0) { return FALSE; } crm_debug_6("max width: %d, first char: %c", field_width, (*str)[0]); if((*str)[0] == '.' || (*str)[0] == ',') { fraction = TRUE; field_width = -1; (*str)++; } else if((*str)[0] == '-') { negate = TRUE; (*str)++; } else if((*str)[0] == '+' || (*str)[0] == ':') { (*str)++; } for(; (fraction || lpc < field_width) && isdigit((int) (*str)[0]); lpc++) { if(fraction) { intermediate = ((*str)[0] - '0')/(10^lpc); } else { *result *= 10; intermediate = (*str)[0] - '0'; } *result += intermediate; (*str)++; } if(fraction) { *result = (int)(*result * uppper_bound); } else if(uppper_bound > 0 && *result > uppper_bound) { *result = uppper_bound; } if(negate) { *result = 0 - *result; } if(lpc > 0) { crm_debug_5("Found int: %d", *result); return TRUE; } return FALSE; } gboolean check_for_ordinal(const char *str) { if(isdigit((int) str[2]) == FALSE) { crm_debug_6("char 3 == %c", str[2]); return FALSE; } if(isspace((int) str[3])) { return TRUE; } else if(str[3] == 0) { return TRUE; } else if(str[3] == 'T') { return TRUE; } else if(str[3] == '/') { return TRUE; } crm_debug_6("char 4 == %c", str[3]); return FALSE; } int str_lookup(const char *str, enum date_fields field) { return 0; } void reset_time(ha_time_t *a_time) { a_time->years = 0; a_time->has->years = FALSE; a_time->weekyears = 0; a_time->has->weekyears = FALSE; a_time->months = 0; a_time->has->months = FALSE; a_time->weeks = 0; a_time->has->weeks = FALSE; a_time->days = 0; a_time->has->days = FALSE; a_time->weekdays = 0; a_time->has->weekdays = FALSE; a_time->yeardays = 0; a_time->has->yeardays = FALSE; a_time->hours = 0; a_time->has->hours = FALSE; a_time->minutes = 0; a_time->has->minutes = FALSE; a_time->seconds = 0; a_time->has->seconds = FALSE; } void reset_tm(struct tm *some_tm) { some_tm->tm_sec = -1; /* seconds after the minute [0-60] */ some_tm->tm_min = -1; /* minutes after the hour [0-59] */ some_tm->tm_hour = -1; /* hours since midnight [0-23] */ some_tm->tm_mday = -1; /* day of the month [1-31] */ some_tm->tm_mon = -1; /* months since January [0-11] */ some_tm->tm_year = -1; /* years since 1900 */ some_tm->tm_wday = -1; /* days since Sunday [0-6] */ some_tm->tm_yday = -1; /* days since January 1 [0-365] */ some_tm->tm_isdst = -1; /* Daylight Savings Time flag */ #if defined(HAVE_TM_GMTOFF) some_tm->tm_gmtoff = -1; /* offset from CUT in seconds */ #endif #if defined(HAVE_TM_ZONE) some_tm->tm_zone = NULL;/* timezone abbreviation */ #endif } gboolean is_date_sane(ha_time_t *a_date) { int ydays = 0; int mdays = 0; int weeks = 0; - CRM_DEV_ASSERT(a_date != NULL); + CRM_CHECK(a_date != NULL, return FALSE); ydays = is_leap_year(a_date->years)?366:365; mdays = days_per_month(a_date->months, a_date->years); weeks = weeks_in_year(a_date->weekyears); crm_debug_5("max ydays: %d, max mdays: %d, max weeks: %d", ydays, mdays, weeks); - CRM_DEV_ASSERT(a_date->has->years); - CRM_DEV_ASSERT(a_date->has->weekyears); + CRM_CHECK(a_date->has->years, return FALSE); + CRM_CHECK(a_date->has->weekyears, return FALSE); - CRM_DEV_ASSERT(a_date->has->months); - CRM_DEV_ASSERT(a_date->months > 0); - CRM_DEV_ASSERT(a_date->months <= 12); + CRM_CHECK(a_date->has->months, return FALSE); + CRM_CHECK(a_date->months > 0, return FALSE); + CRM_CHECK(a_date->months <= 12, return FALSE); - CRM_DEV_ASSERT(a_date->has->weeks); - CRM_DEV_ASSERT(a_date->weeks > 0); - CRM_DEV_ASSERT(a_date->weeks <= weeks); + CRM_CHECK(a_date->has->weeks, return FALSE); + CRM_CHECK(a_date->weeks > 0, return FALSE); + CRM_CHECK(a_date->weeks <= weeks, return FALSE); - CRM_DEV_ASSERT(a_date->has->days); - CRM_DEV_ASSERT(a_date->days > 0); - CRM_DEV_ASSERT(a_date->days <= mdays); + CRM_CHECK(a_date->has->days, return FALSE); + CRM_CHECK(a_date->days > 0, return FALSE); + CRM_CHECK(a_date->days <= mdays, return FALSE); - CRM_DEV_ASSERT(a_date->has->weekdays); - CRM_DEV_ASSERT(a_date->weekdays > 0); - CRM_DEV_ASSERT(a_date->weekdays <= 7); + CRM_CHECK(a_date->has->weekdays, return FALSE); + CRM_CHECK(a_date->weekdays > 0, return FALSE); + CRM_CHECK(a_date->weekdays <= 7, return FALSE); - CRM_DEV_ASSERT(a_date->has->yeardays); - CRM_DEV_ASSERT(a_date->yeardays > 0); - CRM_DEV_ASSERT(a_date->yeardays <= ydays); + CRM_CHECK(a_date->has->yeardays, return FALSE); + CRM_CHECK(a_date->yeardays > 0, return FALSE); + CRM_CHECK(a_date->yeardays <= ydays, return FALSE); - CRM_DEV_ASSERT(a_date->hours >= 0); - CRM_DEV_ASSERT(a_date->hours < 24); + CRM_CHECK(a_date->hours >= 0, return FALSE); + CRM_CHECK(a_date->hours < 24, return FALSE); - CRM_DEV_ASSERT(a_date->minutes >= 0); - CRM_DEV_ASSERT(a_date->minutes < 60); + CRM_CHECK(a_date->minutes >= 0, return FALSE); + CRM_CHECK(a_date->minutes < 60, return FALSE); - CRM_DEV_ASSERT(a_date->seconds >= 0); - CRM_DEV_ASSERT(a_date->seconds <= 60); + CRM_CHECK(a_date->seconds >= 0, return FALSE); + CRM_CHECK(a_date->seconds <= 60, return FALSE); return TRUE; } #define do_cmp_field(lhs, rhs, field) \ { \ if(lhs->field > rhs->field) { \ crm_debug_2("%s: %d > %d", \ #field, lhs->field, rhs->field); \ return 1; \ } else if(lhs->field < rhs->field) { \ crm_debug_2("%s: %d < %d", \ #field, lhs->field, rhs->field); \ return -1; \ } \ } int compare_date(ha_time_t *lhs, ha_time_t *rhs) { normalize_time(lhs); normalize_time(rhs); do_cmp_field(lhs->normalized, rhs->normalized, years); do_cmp_field(lhs->normalized, rhs->normalized, yeardays); do_cmp_field(lhs->normalized, rhs->normalized, hours); do_cmp_field(lhs->normalized, rhs->normalized, minutes); do_cmp_field(lhs->normalized, rhs->normalized, seconds); return 0; } ha_time_t * new_ha_date(gboolean set_to_now) { time_t tm_now; ha_time_t *now = NULL; tzset(); tm_now = time(NULL); crm_malloc0(now, sizeof(ha_time_t)); crm_malloc0(now->has, sizeof(ha_has_time_t)); crm_malloc0(now->offset, sizeof(ha_time_t)); crm_malloc0(now->offset->has, sizeof(ha_has_time_t)); if(set_to_now) { ha_set_timet_time(now, &tm_now); } return now; } void free_ha_date(ha_time_t *a_date) { if(a_date == NULL) { return; } free_ha_date(a_date->normalized); free_ha_date(a_date->offset); crm_free(a_date->has); crm_free(a_date); } void log_tm_date(int log_level, struct tm *some_tm) { const char *tzn; #if defined(HAVE_TM_ZONE) tzn = some_tm->tm_zone; #elif defined(HAVE_TZNAME) tzn = tzname[0]; #else tzn = NULL; #endif crm_log_maybe(log_level, "%.2d/%.2d/%.4d %.2d:%.2d:%.2d %s" " (wday=%d, yday=%d, dst=%d, offset=%ld)", some_tm->tm_mday, some_tm->tm_mon, 1900+some_tm->tm_year, some_tm->tm_hour, some_tm->tm_min, some_tm->tm_sec, tzn, some_tm->tm_wday==0?7:some_tm->tm_wday, 1+some_tm->tm_yday, some_tm->tm_isdst, GMTOFF(some_tm)); } diff --git a/lib/crm/common/utils.c b/lib/crm/common/utils.c index de606277d7..8ad3aa6def 100644 --- a/lib/crm/common/utils.c +++ b/lib/crm/common/utils.c @@ -1,1220 +1,1215 @@ -/* $Id: utils.c,v 1.35 2006/03/17 17:59:32 andrew Exp $ */ +/* $Id: utils.c,v 1.36 2006/03/18 17:23:48 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 #ifndef _GNU_SOURCE # define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef MAXLINE # define MAXLINE 512 #endif static uint ref_counter = 0; gboolean crm_assert_failed = FALSE; unsigned int crm_log_level = LOG_INFO; void crm_set_env_options(void); char * generateReference(const char *custom1, const char *custom2) { const char *local_cust1 = custom1; const char *local_cust2 = custom2; int reference_len = 4; char *since_epoch = NULL; reference_len += 20; /* too big */ reference_len += 40; /* too big */ if(local_cust1 == NULL) { local_cust1 = "_empty_"; } reference_len += strlen(local_cust1); if(local_cust2 == NULL) { local_cust2 = "_empty_"; } reference_len += strlen(local_cust2); crm_malloc0(since_epoch, reference_len*(sizeof(char))); if(since_epoch != NULL) { sprintf(since_epoch, "%s-%s-%ld-%u", local_cust1, local_cust2, (unsigned long)time(NULL), ref_counter++); } return since_epoch; } gboolean decodeNVpair(const char *srcstring, char separator, char **name, char **value) { int lpc = 0; int len = 0; const char *temp = NULL; CRM_ASSERT(name != NULL && value != NULL); *name = NULL; *value = NULL; crm_debug_4("Attempting to decode: [%s]", srcstring); if (srcstring != NULL) { len = strlen(srcstring); while(lpc <= len) { if (srcstring[lpc] == separator) { crm_malloc0(*name, sizeof(char)*lpc+1); if(*name == NULL) { break; /* and return FALSE */ } strncpy(*name, srcstring, lpc); (*name)[lpc] = '\0'; /* this sucks but as the strtok manpage says.. * it *is* a bug */ len = len-lpc; len--; if(len <= 0) { *value = NULL; } else { crm_malloc0(*value, sizeof(char)*len+1); if(*value == NULL) { crm_free(*name); break; /* and return FALSE */ } temp = srcstring+lpc+1; strncpy(*value, temp, len); (*value)[len] = '\0'; } return TRUE; } lpc++; } } if(*name != NULL) { crm_free(*name); } *name = NULL; *value = NULL; return FALSE; } char * crm_concat(const char *prefix, const char *suffix, char join) { int len = 0; char *new_str = NULL; CRM_ASSERT(prefix != NULL); CRM_ASSERT(suffix != NULL); len = strlen(prefix) + strlen(suffix) + 2; crm_malloc0(new_str, sizeof(char)*(len)); sprintf(new_str, "%s%c%s", prefix, join, suffix); new_str[len-1] = 0; return new_str; } char * generate_hash_key(const char *crm_msg_reference, const char *sys) { char *hash_key = crm_concat(sys?sys:"none", crm_msg_reference, '_'); crm_debug_3("created hash key: (%s)", hash_key); return hash_key; } char * generate_hash_value(const char *src_node, const char *src_subsys) { char *hash_value = NULL; if (src_node == NULL || src_subsys == NULL) { return NULL; } if (strcmp(CRM_SYSTEM_DC, src_subsys) == 0) { hash_value = crm_strdup(src_subsys); if (!hash_value) { crm_err("memory allocation failed in " "generate_hash_value()"); } return hash_value; } hash_value = crm_concat(src_node, src_subsys, '_'); crm_info("created hash value: (%s)", hash_value); return hash_value; } gboolean decode_hash_value(gpointer value, char **node, char **subsys) { char *char_value = (char*)value; int value_len = strlen(char_value); crm_info("Decoding hash value: (%s:%d)", char_value, value_len); if (strcmp(CRM_SYSTEM_DC, (char*)value) == 0) { *node = NULL; *subsys = (char*)crm_strdup(char_value); if (*subsys == NULL) { crm_err("memory allocation failed in " "decode_hash_value()"); return FALSE; } crm_info("Decoded value: (%s:%d)", *subsys, (int)strlen(*subsys)); return TRUE; } else if (char_value != NULL) { if (decodeNVpair(char_value, '_', node, subsys)) { return TRUE; } else { *node = NULL; *subsys = NULL; return FALSE; } } return FALSE; } char * crm_itoa(int an_int) { int len = 32; char *buffer = NULL; crm_malloc0(buffer, sizeof(char)*(len+1)); if(buffer != NULL) { snprintf(buffer, len, "%d", an_int); } return buffer; } extern int LogToLoggingDaemon(int priority, const char * buf, int bstrlen, gboolean use_pri_str); gboolean crm_log_init(const char *entity) { /* const char *test = "Testing log daemon connection"; */ /* Redirect messages from glib functions to our handler */ /* cl_malloc_forced_for_glib(); */ g_log_set_handler(NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG | G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL, cl_glib_msg_handler, NULL); /* and for good measure... - this enum is a bit field (!) */ g_log_set_always_fatal((GLogLevelFlags)0); /*value out of range*/ cl_log_set_entity(entity); cl_log_set_facility(LOG_LOCAL7); cl_set_corerootdir(HA_COREDIR); cl_cdtocoredir(); crm_set_env_options(); CL_SIGNAL(DEBUG_INC, alter_debug); CL_SIGNAL(DEBUG_DEC, alter_debug); return TRUE; } /* returns the old value */ unsigned int set_crm_log_level(unsigned int level) { unsigned int old = crm_log_level; while(crm_log_level < level) { alter_debug(DEBUG_INC); } while(crm_log_level > level) { alter_debug(DEBUG_DEC); } return old; } unsigned int get_crm_log_level(void) { return crm_log_level; } void crm_log_message_adv(int level, const char *prefix, const HA_Message *msg) { if((int)crm_log_level >= level) { do_crm_log(level, NULL, NULL, "#========= %s message start ==========#", prefix?prefix:""); if(level > LOG_DEBUG) { cl_log_message(LOG_DEBUG, msg); } else { cl_log_message(level, msg); } } } void do_crm_log(int log_level, const char *file, const char *function, const char *fmt, ...) { int log_as = log_level; gboolean do_log = FALSE; if(log_level <= (int)crm_log_level) { do_log = TRUE; if(log_level > LOG_INFO) { log_as = LOG_DEBUG; } } if(do_log) { va_list ap; int nbytes; char buf[MAXLINE]; va_start(ap, fmt); nbytes=vsnprintf(buf, MAXLINE, fmt, ap); va_end(ap); log_level -= LOG_INFO; if(log_level > 1) { if(file == NULL && function == NULL) { cl_log(log_as, "[%d] %s", log_level, buf); } else { cl_log(log_as, "mask(%s%s%s [%d]): %s", file?file:"", (file !=NULL && function !=NULL)?":":"", function?function:"", log_level, buf); } } else { if(file == NULL && function == NULL) { cl_log(log_as, "%s", buf); } else { cl_log(log_as, "mask(%s%s%s): %s", file?file:"", (file !=NULL && function !=NULL)?":":"", function?function:"", buf); } } if(nbytes > MAXLINE) { cl_log(LOG_WARNING, "Log from %s() was truncated", crm_str(function)); } } } int compare_version(const char *version1, const char *version2) { int lpc = 0; char *step1 = NULL, *step2 = NULL; char *rest1 = NULL, *rest2 = NULL; if(version1 == NULL && version2 == NULL) { return 0; } else if(version1 == NULL) { return -1; } else if(version2 == NULL) { return 1; } if(version1 != NULL) { rest1 = crm_strdup(version1); } else { version1 = ""; } if(version2 != NULL) { rest2 = crm_strdup(version2); } else { version2 = ""; } while(1) { int cmp = 0; int step1_i = 0; int step2_i = 0; char *tmp1 = NULL, *tmp2 = NULL; decodeNVpair(rest1, '.', &step1, &tmp1); decodeNVpair(rest2, '.', &step2, &tmp2); if(step1 != NULL) { step1_i = crm_parse_int(step1, NULL); } if(step2 != NULL) { step2_i = crm_parse_int(step2, NULL); } if(step1_i < step2_i){ cmp = -1; } else if (step1_i > step2_i){ cmp = 1; } crm_debug_4("compare[%d (%d)]: %d(%s) %d(%s)", lpc++, cmp, step1_i, crm_str(step1), step2_i, crm_str(step2)); crm_free(rest1); crm_free(rest2); rest1 = tmp1; rest2 = tmp2; if(step1 == NULL && step2 == NULL) { break; } crm_free(step1); crm_free(step2); if(cmp < 0) { crm_debug_3("%s < %s", version1, version2); return -1; } else if(cmp > 0) { crm_debug_3("%s > %s", version1, version2); return 1; } } crm_debug_3("%s == %s", version1, version2); return 0; } gboolean do_stderr = FALSE; void alter_debug(int nsig) { CL_SIGNAL(DEBUG_INC, alter_debug); CL_SIGNAL(DEBUG_DEC, alter_debug); switch(nsig) { case DEBUG_INC: crm_log_level++; break; case DEBUG_DEC: crm_log_level--; break; default: fprintf(stderr, "Unknown signal %d\n", nsig); cl_log(LOG_ERR, "Unknown signal %d", nsig); break; } } void g_hash_destroy_str(gpointer data) { crm_free(data); } int crm_int_helper(const char *text, char **end_text) { int atoi_result = -1; char *local_end_text = NULL; errno = 0; if(text != NULL) { if(end_text != NULL) { atoi_result = (int)strtol(text, end_text, 10); } else { atoi_result = (int)strtol(text, &local_end_text, 10); } -/* CRM_DEV_ASSERT(errno != EINVAL); */ +/* CRM_CHECK(errno != EINVAL); */ if(errno == EINVAL) { crm_err("Conversion of %s failed", text); atoi_result = -1; } else { if(errno == ERANGE) { crm_err("Conversion of %s was clipped", text); } if(end_text == NULL && local_end_text[0] != '\0') { crm_err("Characters left over after parsing " "\"%s\": \"%s\"", text, local_end_text); } } } return atoi_result; } int crm_parse_int(const char *text, const char *default_text) { int atoi_result = -1; if(text != NULL) { atoi_result = crm_int_helper(text, NULL); if(errno == 0) { return atoi_result; } } if(default_text != NULL) { atoi_result = crm_int_helper(default_text, NULL); if(errno == 0) { return atoi_result; } } else { crm_err("No default conversion value supplied"); } return -1; } gboolean safe_str_eq(const char *a, const char *b) { if(a == b) { return TRUE; } else if(a == NULL || b == NULL) { return FALSE; } else if(strcmp(a, b) == 0) { return TRUE; } return FALSE; } gboolean safe_str_neq(const char *a, const char *b) { if(a == b) { return FALSE; } else if(a==NULL || b==NULL) { return TRUE; } else if(strcmp(a, b) == 0) { return FALSE; } return TRUE; } char * crm_strdup(const char *a) { char *ret = NULL; - CRM_DEV_ASSERT(a != NULL); + CRM_CHECK(a != NULL, return NULL); if(a != NULL) { ret = cl_strdup(a); } else { crm_warn("Cannot dup NULL string"); } return ret; } static GHashTable *crm_uuid_cache = NULL; static GHashTable *crm_uname_cache = NULL; void unget_uuid(const char *uname) { if(crm_uuid_cache == NULL) { return; } g_hash_table_remove(crm_uuid_cache, uname); } const char * get_uuid(ll_cluster_t *hb, const char *uname) { cl_uuid_t uuid_raw; char *uuid_calc = NULL; const char *unknown = "00000000-0000-0000-0000-000000000000"; if(crm_uuid_cache == NULL) { crm_uuid_cache = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); } - CRM_DEV_ASSERT(uname != NULL); + CRM_CHECK(uname != NULL, return NULL); /* avoid blocking calls where possible */ uuid_calc = g_hash_table_lookup(crm_uuid_cache, uname); if(uuid_calc != NULL) { return uuid_calc; } if(hb->llc_ops->get_uuid_by_name(hb, uname, &uuid_raw) == HA_FAIL) { crm_err("get_uuid_by_name() call failed for host %s", uname); crm_free(uuid_calc); return NULL; } crm_malloc0(uuid_calc, sizeof(char)*50); if(uuid_calc == NULL) { return NULL; } cl_uuid_unparse(&uuid_raw, uuid_calc); if(safe_str_eq(uuid_calc, unknown)) { crm_warn("Could not calculate UUID for %s", uname); crm_free(uuid_calc); return NULL; } g_hash_table_insert(crm_uuid_cache, crm_strdup(uname), uuid_calc); uuid_calc = g_hash_table_lookup(crm_uuid_cache, uname); return uuid_calc; } const char * get_uname(ll_cluster_t *hb, const char *uuid) { char *uname = NULL; if(crm_uuid_cache == NULL) { crm_uname_cache = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); } - CRM_DEV_ASSERT(uuid != NULL); + CRM_CHECK(uuid != NULL, return NULL); /* avoid blocking calls where possible */ uname = g_hash_table_lookup(crm_uname_cache, uuid); if(uname != NULL) { return uname; } if(uuid != NULL) { cl_uuid_t uuid_raw; char *uuid_copy = crm_strdup(uuid); cl_uuid_parse(uuid_copy, &uuid_raw); if(hb->llc_ops->get_name_by_uuid( hb, &uuid_raw, uname, 256) == HA_FAIL) { crm_err("Could not calculate UUID for %s", uname); uname = NULL; crm_free(uuid_copy); } else { g_hash_table_insert( crm_uuid_cache, uuid_copy, crm_strdup(uname)); uname = g_hash_table_lookup(crm_uname_cache, uuid); } return uname; } return NULL; } void set_uuid(ll_cluster_t *hb,crm_data_t *node,const char *attr,const char *uname) { const char *uuid_calc = get_uuid(hb, uname); crm_xml_add(node, attr, uuid_calc); return; } void crm_set_ha_options(ll_cluster_t *hb_cluster) { #if 0 int facility; char *param_val = NULL; const char *param_name = NULL; if(hb_cluster == NULL) { crm_set_env_options(); return; } /* change the logging facility to the one used by heartbeat daemon */ crm_debug("Switching to Heartbeat logger"); if (( facility = hb_cluster->llc_ops->get_logfacility(hb_cluster)) > 0) { cl_log_set_facility(facility); } crm_debug_2("Facility: %d", facility); param_name = KEY_LOGFILE; param_val = hb_cluster->llc_ops->get_parameter(hb_cluster, param_name); crm_debug_3("%s = %s", param_name, param_val); if(param_val != NULL) { cl_log_set_logfile(param_val); cl_free(param_val); param_val = NULL; } param_name = KEY_DBGFILE; param_val = hb_cluster->llc_ops->get_parameter(hb_cluster, param_name); crm_debug_3("%s = %s", param_name, param_val); if(param_val != NULL) { cl_log_set_debugfile(param_val); cl_free(param_val); param_val = NULL; } param_name = KEY_DEBUGLEVEL; param_val = hb_cluster->llc_ops->get_parameter(hb_cluster, param_name); crm_debug_3("%s = %s", param_name, param_val); if(param_val != NULL) { int debug_level = crm_parse_int(param_val, NULL); if(debug_level > 0 && (debug_level+LOG_INFO) > (int)crm_log_level) { set_crm_log_level(LOG_INFO + debug_level); } cl_free(param_val); param_val = NULL; } param_name = KEY_LOGDAEMON; param_val = hb_cluster->llc_ops->get_parameter(hb_cluster, param_name); crm_debug_3("%s = %s", param_name, param_val); if(param_val != NULL) { int uselogd; cl_str_to_boolean(param_val, &uselogd); cl_log_set_uselogd(uselogd); if(cl_log_get_uselogd()) { cl_set_logging_wqueue_maxlen(500); } cl_free(param_val); param_val = NULL; } param_name = KEY_CONNINTVAL; param_val = hb_cluster->llc_ops->get_parameter(hb_cluster, param_name); crm_debug_3("%s = %s", param_name, param_val); if(param_val != NULL) { int logdtime; logdtime = crm_get_msec(param_val); cl_log_set_logdtime(logdtime); cl_free(param_val); param_val = NULL; } #endif } #define ENV_PREFIX "HA_" void crm_set_env_options(void) { char *param_val = NULL; const char *param_name = NULL; /* apparently we're not allowed to free the result of getenv */ param_name = ENV_PREFIX "" KEY_DEBUGLEVEL; param_val = getenv(param_name); if(param_val != NULL) { int debug_level = crm_parse_int(param_val, NULL); if(debug_level > 0 && (debug_level+LOG_INFO) > (int)crm_log_level) { set_crm_log_level(LOG_INFO + debug_level); } crm_debug("%s = %s", param_name, param_val); param_val = NULL; } param_name = ENV_PREFIX "" KEY_FACILITY; param_val = getenv(param_name); crm_debug("%s = %s", param_name, param_val); if(param_val != NULL) { int facility = cl_syslogfac_str2int(param_val); if(facility > 0) { cl_log_set_facility(facility); } param_val = NULL; } param_name = ENV_PREFIX "" KEY_LOGFILE; param_val = getenv(param_name); crm_debug("%s = %s", param_name, param_val); if(param_val != NULL) { if(safe_str_eq("/dev/null", param_val)) { param_val = NULL; } cl_log_set_logfile(param_val); param_val = NULL; } param_name = ENV_PREFIX "" KEY_DBGFILE; param_val = getenv(param_name); crm_debug("%s = %s", param_name, param_val); if(param_val != NULL) { if(safe_str_eq("/dev/null", param_val)) { param_val = NULL; } cl_log_set_debugfile(param_val); param_val = NULL; } param_name = ENV_PREFIX "" KEY_LOGDAEMON; param_val = getenv(param_name); crm_debug("%s = %s", param_name, param_val); if(param_val != NULL) { int uselogd; cl_str_to_boolean(param_val, &uselogd); cl_log_set_uselogd(uselogd); if(uselogd) { cl_set_logging_wqueue_maxlen(500); cl_log_set_logd_channel_source(NULL, NULL); } param_val = NULL; } param_name = ENV_PREFIX "" KEY_CONNINTVAL; param_val = getenv(param_name); crm_debug("%s = %s", param_name, param_val); if(param_val != NULL) { int logdtime; logdtime = crm_get_msec(param_val); cl_log_set_logdtime(logdtime); param_val = NULL; } inherit_compress(); } gboolean crm_is_true(const char * s) { gboolean ret = FALSE; if(s != NULL) { cl_str_to_boolean(s, &ret); } return ret; } int crm_str_to_boolean(const char * s, int * ret) { if(s == NULL) { return -1; } else if (strcasecmp(s, "true") == 0 || strcasecmp(s, "on") == 0 || strcasecmp(s, "yes") == 0 || strcasecmp(s, "y") == 0 || strcasecmp(s, "1") == 0){ *ret = TRUE; return 1; } else if (strcasecmp(s, "false") == 0 || strcasecmp(s, "off") == 0 || strcasecmp(s, "no") == 0 || strcasecmp(s, "n") == 0 || strcasecmp(s, "0") == 0){ *ret = FALSE; return 1; } return -1; } #ifndef NUMCHARS # define NUMCHARS "0123456789." #endif #ifndef WHITESPACE # define WHITESPACE " \t\n\r\f" #endif long crm_get_msec(const char * input) { const char * cp = input; const char * units; long multiplier = 1000; long divisor = 1; long ret = -1; double dret; if(input == NULL) { return 0; } cp += strspn(cp, WHITESPACE); units = cp + strspn(cp, NUMCHARS); units += strspn(units, WHITESPACE); if (strchr(NUMCHARS, *cp) == NULL) { return ret; } if (strncasecmp(units, "ms", 2) == 0 || strncasecmp(units, "msec", 4) == 0) { multiplier = 1; divisor = 1; }else if (strncasecmp(units, "us", 2) == 0 || strncasecmp(units, "usec", 4) == 0) { multiplier = 1; divisor = 1000; }else if (strncasecmp(units, "s", 1) == 0 || strncasecmp(units, "sec", 3) == 0) { multiplier = 1000; divisor = 1; }else if (strncasecmp(units, "m", 1) == 0 || strncasecmp(units, "min", 3) == 0) { multiplier = 60*1000; divisor = 1; }else if (*units != EOS && *units != '\n' && *units != '\r') { return ret; } dret = atof(cp); dret *= (double)multiplier; dret /= (double)divisor; dret += 0.5; ret = (long)dret; return(ret); } gboolean ccm_have_quorum(oc_ed_t event) { if(event==OC_EV_MS_NEW_MEMBERSHIP) { return TRUE; } return FALSE; } const char * ccm_event_name(oc_ed_t event) { if(event==OC_EV_MS_NEW_MEMBERSHIP) { return "NEW MEMBERSHIP"; } else if(event==OC_EV_MS_NOT_PRIMARY) { return "NOT PRIMARY"; } else if(event==OC_EV_MS_PRIMARY_RESTORED) { return "PRIMARY RESTORED"; } else if(event==OC_EV_MS_EVICTED) { return "EVICTED"; } else if(event==OC_EV_MS_INVALID) { return "INVALID"; } return "NO QUORUM MEMBERSHIP"; } const char * op_status2text(op_status_t status) { switch(status) { case LRM_OP_PENDING: return "pending"; break; case LRM_OP_DONE: return "complete"; break; case LRM_OP_ERROR: return "Error"; break; case LRM_OP_TIMEOUT: return "Timed Out"; break; case LRM_OP_NOTSUPPORTED: return "NOT SUPPORTED"; break; case LRM_OP_CANCELLED: return "Cancelled"; break; } - CRM_DEV_ASSERT(status >= LRM_OP_PENDING && status <= LRM_OP_CANCELLED); - crm_err("Unknown status: %d", status); + CRM_CHECK(status >= LRM_OP_PENDING && status <= LRM_OP_CANCELLED, + crm_err("Unknown status: %d", status)); return "UNKNOWN!"; } char * generate_op_key(const char *rsc_id, const char *op_type, int interval) { int len = 35; char *op_id = NULL; - CRM_DEV_ASSERT(rsc_id != NULL); if(crm_assert_failed) { return NULL; } - CRM_DEV_ASSERT(op_type != NULL); if(crm_assert_failed) { return NULL; } + CRM_CHECK(rsc_id != NULL, return NULL); + CRM_CHECK(op_type != NULL, return NULL); len += strlen(op_type); len += strlen(rsc_id); crm_malloc0(op_id, sizeof(char)*len); if(op_id != NULL) { sprintf(op_id, "%s_%s_%d", rsc_id, op_type, interval); } return op_id; } char * generate_notify_key(const char *rsc_id, const char *notify_type, const char *op_type) { int len = 12; char *op_id = NULL; - CRM_DEV_ASSERT(rsc_id != NULL); if(crm_assert_failed) { return NULL; } - CRM_DEV_ASSERT(op_type != NULL); if(crm_assert_failed) { return NULL; } - CRM_DEV_ASSERT(notify_type != NULL); if(crm_assert_failed) { return NULL; } + CRM_CHECK(rsc_id != NULL, return NULL); + CRM_CHECK(op_type != NULL, return NULL); + CRM_CHECK(notify_type != NULL, return NULL); len += strlen(op_type); len += strlen(rsc_id); len += strlen(notify_type); crm_malloc0(op_id, sizeof(char)*len); if(op_id != NULL) { sprintf(op_id, "%s_%s_notify_%s_0", rsc_id, notify_type, op_type); } return op_id; } char * generate_transition_magic_v202(const char *transition_key, int op_status) { int len = 80; char *fail_state = NULL; - CRM_DEV_ASSERT(transition_key != NULL); - if(crm_assert_failed) { return NULL; } + CRM_CHECK(transition_key != NULL, return NULL); len += strlen(transition_key); crm_malloc0(fail_state, sizeof(char)*len); if(fail_state != NULL) { snprintf(fail_state, len, "%d:%s", op_status,transition_key); } return fail_state; } char * generate_transition_magic(const char *transition_key, int op_status, int op_rc) { int len = 80; char *fail_state = NULL; - CRM_DEV_ASSERT(transition_key != NULL); - if(crm_assert_failed) { return NULL; } + CRM_CHECK(transition_key != NULL, return NULL); len += strlen(transition_key); crm_malloc0(fail_state, sizeof(char)*len); if(fail_state != NULL) { snprintf(fail_state, len, "%d:%d;%s", op_status, op_rc, transition_key); } return fail_state; } gboolean decode_transition_magic( const char *magic, char **uuid, int *transition_id, int *op_status, int *op_rc) { char *rc = NULL; char *key = NULL; char *magic2 = NULL; char *status = NULL; if(decodeNVpair(magic, ':', &status, &magic2) == FALSE) { crm_err("Couldn't find ':' in: %s", magic); return FALSE; } if(decodeNVpair(magic2, ';', &rc, &key) == FALSE) { crm_err("Couldn't find ';' in: %s", magic2); return FALSE; } - CRM_DEV_ASSERT(decode_transition_key(key, uuid, transition_id)); - if(crm_assert_failed) { - return FALSE; - } + CRM_CHECK(decode_transition_key(key, uuid, transition_id), return FALSE); *op_rc = crm_parse_int(rc, NULL); *op_status = crm_parse_int(status, NULL); crm_free(rc); crm_free(key); crm_free(magic2); crm_free(status); return TRUE; } char * generate_transition_key(int transition_id, const char *node) { int len = 40; char *fail_state = NULL; - CRM_DEV_ASSERT(node != NULL); if(crm_assert_failed) { return NULL; } + CRM_CHECK(node != NULL, return NULL); len += strlen(node); crm_malloc0(fail_state, sizeof(char)*len); if(fail_state != NULL) { snprintf(fail_state, len, "%d:%s", transition_id, node); } return fail_state; } gboolean decode_transition_key(const char *key, char **uuid, int *transition_id) { char *transition = NULL; if(decodeNVpair(key, ':', &transition, uuid) == FALSE) { crm_err("Couldn't find ':' in: %s", key); return FALSE; } *transition_id = crm_parse_int(transition, NULL); crm_free(transition); return TRUE; } gboolean crm_mem_stats(volatile cl_mem_stats_t *mem_stats) { volatile cl_mem_stats_t *active_stats = mem_stats; if(active_stats == NULL) { active_stats = cl_malloc_getstats(); } - CRM_DEV_ASSERT(active_stats != NULL); + CRM_CHECK(active_stats != NULL, ;); #ifndef CRM_USE_MALLOC if(active_stats->numalloc > active_stats->numfree) { crm_warn("Potential memory leak detected:" " %lu alloc's vs. %lu free's (%lu)" " (%lu bytes not freed: req=%lu, alloc'd=%lu)", active_stats->numalloc, active_stats->numfree, active_stats->numalloc - active_stats->numfree, active_stats->nbytes_alloc, active_stats->nbytes_req, active_stats->mallocbytes); return TRUE; } else if(active_stats->numalloc < active_stats->numfree) { crm_debug("Process shrank: %lu alloc's vs. %lu free's (%lu)", active_stats->numalloc, active_stats->numfree, active_stats->numalloc - active_stats->numfree); } #endif return FALSE; } void crm_zero_mem_stats(volatile cl_mem_stats_t *stats) { volatile cl_mem_stats_t *active_stats = NULL; if(stats != NULL) { cl_malloc_setstats(stats); } active_stats = cl_malloc_getstats(); active_stats->numalloc = 0; active_stats->numfree = 0; active_stats->numrealloc = 0; active_stats->nbytes_req = 0; active_stats->nbytes_alloc = 0; active_stats->mallocbytes = 0; active_stats->arena = 0; } void crm_abort(const char *file, const char *function, int line, const char *assert_condition, gboolean do_fork) { int pid = 0; if(do_fork) { pid=fork(); } switch(pid) { case -1: crm_err("Cannot fork!"); return; default: /* Parent */ crm_debug("Child %d forked to record assert failure", pid); return; case 0: /* Child */ break; } /* create a new process group to avoid * being interupted by heartbeat */ setpgid(0, 0); do_crm_log(LOG_ERR, file, function, "Triggered %sfatal assert at %s:%d : %s", do_fork?"non-":"", file, line, assert_condition); abort(); } diff --git a/lib/crm/common/xml.c b/lib/crm/common/xml.c index a9dd28920e..e1728d59e3 100644 --- a/lib/crm/common/xml.c +++ b/lib/crm/common/xml.c @@ -1,2299 +1,2256 @@ -/* $Id: xml.c,v 1.60 2006/03/17 15:08:52 davidlee Exp $ */ +/* $Id: xml.c,v 1.61 2006/03/18 17:23:48 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 int is_comment_start(const char *input); int is_comment_end(const char *input); gboolean drop_comments(const char *input, int *offset); void dump_array( int log_level, const char *message, const char **array, int depth); int print_spaces(char *buffer, int spaces); int log_data_element(const char *function, const char *prefix, int log_level, int depth, const crm_data_t *data, gboolean formatted); int dump_data_element( int depth, char **buffer, const crm_data_t *data, gboolean formatted); crm_data_t *parse_xml(const char *input, int *offset); int get_tag_name(const char *input); int get_attr_name(const char *input); int get_attr_value(const char *input); gboolean can_prune_leaf(crm_data_t *xml_node); void diff_filter_context(int context, int upper_bound, int lower_bound, crm_data_t *xml_node, crm_data_t *parent); int in_upper_context(int depth, int context, crm_data_t *xml_node); crm_data_t * find_xml_node(crm_data_t *root, const char * search_path, gboolean must_find) { if(must_find || root != NULL) { crm_validate_data(root); } if(search_path == NULL) { crm_warn("Will never find "); return NULL; } xml_child_iter_filter( root, a_child, search_path, /* crm_debug_5("returning node (%s).", xmlGetNodePath(a_child)); */ crm_log_xml_debug_5(a_child, "contents\t%s"); crm_log_xml_debug_5(root, "found in\t%s"); crm_validate_data(a_child); return a_child; ); if(must_find) { crm_warn("Could not find %s in %s.", search_path, xmlGetNodePath(root)); } else if(root != NULL) { crm_debug_3("Could not find %s in %s.", search_path, xmlGetNodePath(root)); } else { crm_debug_3("Could not find %s in .", search_path); } return NULL; } crm_data_t* find_xml_node_nested(crm_data_t *root, const char **search_path, int len) { int j; gboolean is_found = TRUE; crm_data_t *match = NULL; crm_data_t *lastMatch = root; crm_validate_data(root); if(search_path == NULL || search_path[0] == NULL) { crm_warn("Will never find NULL"); return NULL; } dump_array(LOG_DEBUG_5, "Looking for.", search_path, len); for (j=0; j < len; ++j) { if (search_path[j] == NULL) { /* a NULL also means stop searching */ break; } match = find_xml_node(lastMatch, search_path[j], FALSE); if(match == NULL) { is_found = FALSE; break; } else { lastMatch = match; } } if (is_found) { crm_debug_5("returning node (%s).", xmlGetNodePath(lastMatch)); crm_log_xml_debug_5(lastMatch, "found\t%s"); crm_log_xml_debug_5(root, "in \t%s"); crm_validate_data(lastMatch); return lastMatch; } dump_array(LOG_DEBUG_2, "Could not find the full path to the node you specified.", search_path, len); crm_debug_2("Closest point was node (%s) starting from %s.", xmlGetNodePath(lastMatch), crm_element_name(root)); return NULL; } const char * get_xml_attr_nested(crm_data_t *parent, const char **node_path, int length, const char *attr_name, gboolean error) { const char *attr_value = NULL; crm_data_t *attr_parent = NULL; if(error || parent != NULL) { crm_validate_data(parent); } if(parent == NULL) { crm_debug_3("Can not find attribute %s in NULL parent",attr_name); return NULL; } if(attr_name == NULL || strlen(attr_name) == 0) { crm_err("Can not find attribute with no name in %s", xmlGetNodePath(parent)); return NULL; } if(length == 0) { attr_parent = parent; } else { attr_parent = find_xml_node_nested(parent, node_path, length); if(attr_parent == NULL && error) { crm_err("No node at the path you specified."); return NULL; } } attr_value = crm_element_value(attr_parent, attr_name); if((attr_value == NULL || strlen(attr_value) == 0) && error) { crm_err("No value present for %s at %s", attr_name, xmlGetNodePath(attr_parent)); return NULL; } return attr_value; } crm_data_t* find_entity(crm_data_t *parent, const char *node_name, const char *id) { crm_validate_data(parent); xml_child_iter_filter( parent, a_child, node_name, if(id == NULL || safe_str_eq(id, ID(a_child))) { crm_debug_4("returning node (%s).", xmlGetNodePath(a_child)); return a_child; } ); crm_debug_3("node <%s id=%s> not found in %s.", node_name, id, xmlGetNodePath(parent)); return NULL; } void copy_in_properties(crm_data_t* target, const crm_data_t *src) { int value_len = 0; char *incr_value = NULL; char *new_value = NULL; crm_validate_data(src); crm_validate_data(target); if(src == NULL) { crm_warn("No node to copy properties from"); } else if (target == NULL) { crm_err("No node to copy properties into"); } else { xml_prop_iter( src, local_prop_name, local_prop_value, /* if the value is name followed by "++" we need * to increment the existing value */ new_value = NULL; incr_value = NULL; /* do a quick check to decide if its worth * constructing the various strings and * performing string comparisions */ value_len = strlen(local_prop_value); if(value_len > 2 && local_prop_value[0] == local_prop_value[0] && local_prop_value[value_len-1] == '+' && local_prop_value[value_len-2] == '+') { int old_int = 0; const char *old_value = NULL; incr_value=crm_concat(local_prop_name,"+",'+'); if(safe_str_eq(local_prop_value, incr_value)) { old_value = crm_element_value( target, local_prop_name); old_int = crm_parse_int(old_value, "0"); new_value = crm_itoa(old_int + 1); local_prop_value = new_value; } } crm_xml_add(target, local_prop_name, local_prop_value); crm_free(incr_value); crm_free(new_value); ); crm_validate_data(target); } return; } crm_data_t* add_node_copy(crm_data_t *new_parent, const crm_data_t *xml_node) { crm_data_t *node_copy = NULL; crm_validate_data(new_parent); crm_validate_data(xml_node); if(xml_node != NULL && new_parent != NULL) { const char *name = crm_element_name(xml_node); - CRM_DEV_ASSERT( - HA_OK == ha_msg_addstruct_compress(new_parent, name, xml_node)); + CRM_CHECK( + HA_OK == ha_msg_addstruct_compress(new_parent, name, xml_node), return NULL); node_copy = find_entity( new_parent, crm_element_name(xml_node), ID(xml_node)); crm_validate_data(node_copy); crm_update_parents(new_parent); crm_validate_data(new_parent); } else if(xml_node == NULL) { crm_err("Could not add copy of NULL node"); } else { crm_err("Could not add copy of node to NULL parent"); } crm_validate_data(node_copy); return node_copy; } const char * crm_xml_add(crm_data_t* node, const char *name, const char *value) { const char *parent_name = NULL; if(node != NULL) { parent_name = crm_element_name(node); } crm_debug_5("[%s] Setting %s to %s", crm_str(parent_name), name, value); if (name == NULL || strlen(name) <= 0) { } else if(node == NULL) { } else if(parent_name == NULL && strcmp(name, F_XML_TAGNAME) != 0) { } else if (value == NULL || strlen(value) <= 0) { xml_remove_prop(node, name); return NULL; } else { const char *new_value = NULL; crm_validate_data(node); ha_msg_mod(node, name, value); new_value = crm_element_value(node, name); return new_value; } return NULL; } const char * crm_xml_add_int(crm_data_t* node, const char *name, int value) { const char *parent_name = NULL; if(node != NULL) { parent_name = crm_element_name(node); } crm_debug_5("[%s] Setting %s to %d", crm_str(parent_name), name, value); if (name == NULL || strlen(name) <= 0) { } else if(node == NULL) { } else if(parent_name == NULL && strcmp(name, F_XML_TAGNAME) != 0) { } else { crm_validate_data(node); ha_msg_mod_int(node, name, value); return crm_element_value(node, name); } return NULL; } crm_data_t* create_xml_node(crm_data_t *parent, const char *name) { const char *local_name = NULL; const char *parent_name = NULL; crm_data_t *ret_value = NULL; if (name == NULL || strlen(name) < 1) { ret_value = NULL; } else { local_name = name; ret_value = ha_msg_new(1); - CRM_DEV_ASSERT(ret_value != NULL); + CRM_CHECK(ret_value != NULL, return NULL); crm_xml_add(ret_value, F_XML_TAGNAME, name); crm_validate_data(ret_value); if(parent) { crm_validate_data(parent); parent_name = crm_element_name(parent); crm_debug_5("Attaching %s to parent %s", local_name, parent_name); - CRM_DEV_ASSERT(HA_OK == ha_msg_addstruct( - parent, name, ret_value)); + CRM_CHECK(HA_OK == ha_msg_addstruct( + parent, name, ret_value), return NULL); crm_msg_del(ret_value); crm_update_parents(parent); crm_validate_data(parent); ret_value = parent->values[parent->nfields-1]; crm_validate_data(ret_value); } } crm_debug_5("Created node [%s [%s]]", crm_str(parent_name), crm_str(local_name)); /* set_node_tstamp(ret_value); */ return ret_value; } void free_xml_from_parent(crm_data_t *parent, crm_data_t *a_node) { - CRM_DEV_ASSERT(parent != NULL); - if(parent == NULL) { - return; - } else if(a_node == NULL) { - return; - } + CRM_CHECK(parent != NULL, return); + CRM_CHECK(a_node != NULL, return); + crm_validate_data(parent); cl_msg_remove_value(parent, a_node); crm_validate_data(parent); } void free_xml_fn(crm_data_t *a_node) { if(a_node == NULL) { ; /* nothing to do */ } else { int has_parent = 0; crm_validate_data(a_node); ha_msg_value_int(a_node, F_XML_PARENT, &has_parent); /* there is no way in hell we should be deleting anything * with a parent and without the parent knowning */ - CRM_DEV_ASSERT(has_parent == 0); + CRM_CHECK(has_parent == 0, return); if(has_parent == 0) { crm_validate_data(a_node); crm_msg_del(a_node); } } return; } void set_node_tstamp(crm_data_t *a_node) { #if 0 char *since_epoch = NULL; time_t a_time = time(NULL); crm_validate_data(a_node); if(a_time == (time_t)-1) { cl_perror("set_node_tstamp(): Invalid time returned"); return; } crm_malloc0(since_epoch, 128*(sizeof(char))); if(since_epoch != NULL) { sprintf(since_epoch, "%ld", (unsigned long)a_time); ha_msg_mod(a_node, XML_ATTR_TSTAMP, since_epoch); crm_validate_data(a_node); crm_free(since_epoch); } #endif } crm_data_t* copy_xml(const crm_data_t *src_node) { crm_data_t *new_xml = NULL; - CRM_DEV_ASSERT(src_node != NULL); - CRM_DEV_ASSERT(crm_element_name(src_node) != NULL); + CRM_CHECK(src_node != NULL, return NULL); + CRM_CHECK(crm_element_name(src_node) != NULL, return NULL); - if(src_node == NULL) { - crm_warn("Attempt to dup NULL XML"); - return NULL; - - } else if(crm_element_name(src_node) == NULL) { - crm_log_xml_err(src_node, "Attempt to dup XML with no name"); - return NULL; - } - crm_validate_data(src_node); new_xml = ha_msg_copy(src_node); crm_set_element_parent(new_xml, NULL); crm_update_parents(new_xml); crm_validate_data(new_xml); return new_xml; } crm_data_t* string2xml(const char *input) { crm_data_t *output = parse_xml(input, NULL); if(output != NULL) { crm_update_parents(output); crm_validate_data(output); } return output; } crm_data_t * stdin2xml(void) { int lpc = 0; int MAX_XML_BUFFER = 20000; int ch = 0; gboolean more = TRUE; gboolean inTag = FALSE; FILE *input = stdin; char *xml_buffer = NULL; crm_data_t *xml_obj = NULL; crm_malloc0(xml_buffer, sizeof(char)*(MAX_XML_BUFFER+1)); while (more && lpc < MAX_XML_BUFFER) { ch = fgetc(input); /* crm_debug_3("Got [%c]", ch); */ switch(ch) { case EOF: case 0: ch = 0; more = FALSE; xml_buffer[lpc++] = ch; break; case '>': case '<': inTag = TRUE; if(ch == '>') { inTag = FALSE; } xml_buffer[lpc++] = ch; break; case '\n': case '\r': case '\t': case ' ': ch = ' '; if(inTag) { xml_buffer[lpc++] = ch; } break; default: xml_buffer[lpc++] = ch; break; } } xml_buffer[MAX_XML_BUFFER] = 0; xml_obj = string2xml(xml_buffer); crm_free(xml_buffer); crm_log_xml_debug_3(xml_obj, "Created fragment"); return xml_obj; } crm_data_t* file2xml(FILE *input) { char *buffer = NULL; crm_data_t *new_obj = NULL; int start = 0, length = 0, read_len = 0; if(input == NULL) { crm_err("No file to read"); return NULL; } /* see how big the file is */ start = ftell(input); fseek(input, 0L, SEEK_END); length = ftell(input); fseek(input, 0L, start); CRM_ASSERT(start == ftell(input)); crm_debug_3("Reading %d bytes from file", length); crm_malloc0(buffer, sizeof(char) * (length+1)); read_len = fread(buffer, sizeof(char), length, input); if(read_len != length) { crm_err("Calculated and read bytes differ: %d vs. %d", length, read_len); } else if(length > 0) { new_obj = string2xml(buffer); } else { crm_warn("File contained no XML"); } crm_free(buffer); return new_obj; } void dump_array(int log_level, const char *message, const char **array, int depth) { int j; if(message != NULL) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s", message); } do_crm_log(log_level, __FILE__, __FUNCTION__, "Contents of the array:"); if(array == NULL || array[0] == NULL || depth == 0) { do_crm_log(log_level, __FILE__, __FUNCTION__, "\t"); return; } for (j=0; j < depth && array[j] != NULL; j++) { if (array[j] == NULL) { break; } do_crm_log(log_level, __FILE__, __FUNCTION__, "\t--> (%s).", array[j]); } } int write_xml_file(crm_data_t *xml_node, const char *filename) { int res = 0; char *now_str = NULL; time_t now; - CRM_DEV_ASSERT(filename != NULL); + CRM_CHECK(filename != NULL, return -1); crm_debug_3("Writing XML out to %s", filename); crm_validate_data(xml_node); if (xml_node == NULL) { crm_err("Cannot write NULL to %s", filename); return -1; } crm_validate_data(xml_node); crm_log_xml_debug_4(xml_node, "Writing out"); crm_validate_data(xml_node); now = time(NULL); now_str = ctime(&now); now_str[24] = EOS; /* replace the newline */ crm_xml_add(xml_node, "last_written", now_str); crm_validate_data(xml_node); { FILE *file_output_strm = fopen(filename, "w"); if(file_output_strm == NULL) { res = -1; cl_perror("Cannot write to %s", filename); } else { char *buffer = dump_xml_formatted(xml_node); - CRM_DEV_ASSERT(buffer != NULL && strlen(buffer) > 0); + CRM_CHECK(buffer != NULL && strlen(buffer) > 0, return -1); if(buffer != NULL && strlen(buffer) > 0) { res = fprintf(file_output_strm, "%s", buffer); if(res < 0) { cl_perror("Cannot write output to %s", filename); } } fflush(file_output_strm); fclose(file_output_strm); crm_free(buffer); } } crm_debug_3("Saved %d bytes to the Cib as XML", res); return res; } void print_xml_formatted(int log_level, const char *function, const crm_data_t *msg, const char *text) { if(msg == NULL) { do_crm_log(log_level,NULL,function, "%s: NULL", crm_str(text)); return; } crm_validate_data(msg); log_data_element(function, text, log_level, 0, msg, TRUE); return; } crm_data_t * get_message_xml(HA_Message *msg, const char *field) { crm_data_t *xml_node = NULL; crm_data_t *tmp_node = NULL; crm_validate_data(msg); tmp_node = cl_get_struct(msg, field); if(tmp_node != NULL) { xml_node = copy_xml(tmp_node); } return xml_node; } gboolean add_message_xml(HA_Message *msg, const char *field, const crm_data_t *xml) { crm_validate_data(xml); crm_validate_data(msg); - CRM_DEV_ASSERT(field != NULL); + CRM_CHECK(field != NULL, return FALSE); ha_msg_addstruct_compress(msg, field, xml); crm_update_parents(msg); return TRUE; } char * dump_xml_formatted(const crm_data_t *an_xml_node) { char *buffer = NULL; char *mutable_ptr = NULL; if(an_xml_node == NULL) { return NULL; } crm_malloc0(buffer, 3*get_stringlen(an_xml_node)); mutable_ptr = buffer; crm_validate_data(an_xml_node); - CRM_DEV_ASSERT(dump_data_element( - 0, &mutable_ptr, an_xml_node, TRUE) >= 0); - if(crm_assert_failed) { - crm_crit("Could not dump the whole message"); - } + CRM_CHECK(dump_data_element( + 0, &mutable_ptr, an_xml_node, TRUE) >= 0, + crm_crit("Could not dump the whole message")); crm_debug_4("Dumped: %s", buffer); return buffer; } char * dump_xml_unformatted(const crm_data_t *an_xml_node) { char *buffer = NULL; char *mutable_ptr = NULL; crm_malloc0(buffer, 2*get_stringlen(an_xml_node)); mutable_ptr = buffer; crm_validate_data(an_xml_node); - CRM_DEV_ASSERT(dump_data_element( - 0, &mutable_ptr, an_xml_node, TRUE) >= 0); - if(crm_assert_failed) { - crm_crit("Could not dump the whole message"); - } + CRM_CHECK(dump_data_element( + 0, &mutable_ptr, an_xml_node, TRUE) >= 0, + crm_crit("Could not dump the whole message")); crm_debug_4("Dumped: %s", buffer); return buffer; } #define update_buffer_head(buffer, len) if(len < 0) { \ (*buffer) = EOS; return -1; \ } else { \ buffer += len; \ } int print_spaces(char *buffer, int depth) { int lpc = 0; int spaces = 2*depth; /* <= so that we always print 1 space - prevents problems with syslog */ for(lpc = 0; lpc <= spaces; lpc++) { if(sprintf(buffer, "%c", ' ') < 1) { return -1; } buffer += 1; } return lpc; } int log_data_element( const char *function, const char *prefix, int log_level, int depth, const crm_data_t *data, gboolean formatted) { int printed = 0; int child_result = 0; int has_children = 0; char print_buffer[1000]; char *buffer = print_buffer; const char *name = crm_element_name(data); crm_debug_5("Dumping %s...", name); crm_validate_data(data); if(data == NULL) { crm_warn("No data to dump as XML"); return 0; } else if(name == NULL && depth == 0) { xml_child_iter( data, a_child, child_result = log_data_element( function, prefix, log_level, depth, a_child, formatted); if(child_result < 0) { return child_result; } ); return 0; } else if(name == NULL) { crm_err("Cannot dump NULL element at depth %d", depth); return -1; } if(formatted) { printed = print_spaces(buffer, depth); update_buffer_head(buffer, printed); } printed = sprintf(buffer, "<%s", name); update_buffer_head(buffer, printed); xml_prop_iter( data, prop_name, prop_value, if(safe_str_eq(F_XML_TAGNAME, prop_name)) { continue; } else if(safe_str_eq(F_XML_PARENT, prop_name)) { continue; } crm_debug_5("Dumping <%s %s=\"%s\"...", name, prop_name, prop_value); printed = sprintf(buffer, " %s=\"%s\"", prop_name, prop_value); update_buffer_head(buffer, printed); ); xml_child_iter( data, child, if(child != NULL) { has_children++; break; } ); printed = sprintf(buffer, "%s>", has_children==0?"/":""); update_buffer_head(buffer, printed); do_crm_log(log_level, function, NULL, "%s%s", prefix?prefix:"", print_buffer); buffer = print_buffer; if(has_children == 0) { return 0; } xml_child_iter( data, a_child, child_result = log_data_element( function, prefix, log_level, depth+1, a_child, formatted); if(child_result < 0) { return -1; } ); if(formatted) { printed = print_spaces(buffer, depth); update_buffer_head(buffer, printed); } do_crm_log(log_level, function, NULL, "%s%s", prefix?prefix:"", print_buffer, name); crm_debug_5("Dumped %s...", name); return has_children; } int dump_data_element( int depth, char **buffer, const crm_data_t *data, gboolean formatted) { int printed = 0; int child_result = 0; int has_children = 0; const char *name = crm_element_name(data); crm_debug_5("Dumping %s...", name); crm_validate_data(data); if(buffer == NULL || *buffer == NULL) { crm_err("No buffer supplied to dump XML into"); return -1; } else if(data == NULL) { crm_warn("No data to dump as XML"); (*buffer)[0] = EOS; return 0; } else if(name == NULL && depth == 0) { xml_child_iter( data, a_child, child_result = dump_data_element( depth, buffer, a_child, formatted); if(child_result < 0) { return child_result; } ); return 0; } else if(name == NULL) { crm_err("Cannot dump NULL element at depth %d", depth); return -1; } if(formatted) { printed = print_spaces(*buffer, depth); update_buffer_head(*buffer, printed); } printed = sprintf(*buffer, "<%s", name); update_buffer_head(*buffer, printed); xml_prop_iter(data, prop_name, prop_value, if(safe_str_eq(F_XML_TAGNAME, prop_name)) { continue; } else if(safe_str_eq(F_XML_PARENT, prop_name)) { continue; } crm_debug_5("Dumping <%s %s=\"%s\"...", name, prop_name, prop_value); printed = sprintf(*buffer, " %s=\"%s\"", prop_name, prop_value); update_buffer_head(*buffer, printed); ); xml_child_iter( data, child, if(child != NULL) { has_children++; break; } ); printed = sprintf(*buffer, "%s>%s", has_children==0?"/":"", formatted?"\n":""); update_buffer_head(*buffer, printed); if(has_children == 0) { return 0; } xml_child_iter( data, child, child_result = dump_data_element( depth+1, buffer, child, formatted); if(child_result < 0) { return -1; } ); if(formatted) { printed = print_spaces(*buffer, depth); update_buffer_head(*buffer, printed); } printed = sprintf(*buffer, "%s", name, formatted?"\n":""); update_buffer_head(*buffer, printed); crm_debug_5("Dumped %s...", name); return has_children; } gboolean xml_has_children(crm_data_t *xml_root) { crm_validate_data(xml_root); xml_child_iter( xml_root, a_child, return TRUE; ); return FALSE; } void xml_validate(const crm_data_t *xml_root) { int lpc = 0; CRM_ASSERT(xml_root != NULL); CRM_ASSERT(cl_is_allocated(xml_root) == 1); CRM_ASSERT(xml_root->nfields < 500); for (lpc = 0; lpc < xml_root->nfields; lpc++) { void *child = xml_root->values[lpc]; CRM_ASSERT(cl_is_allocated(xml_root->names[lpc]) == 1); if(child == NULL) { } else if(xml_root->types[lpc] == FT_STRUCT || xml_root->types[lpc] == FT_UNCOMPRESS) { crm_validate_data(child); } else if(xml_root->types[lpc] == FT_STRING) { CRM_ASSERT(cl_is_allocated(child) == 1); /* } else { */ -/* CRM_DEV_ASSERT(FALSE); */ +/* CRM_CHECK(FALSE); */ } } } void crm_set_element_parent(crm_data_t *data, crm_data_t *parent) { crm_validate_data(data); if(parent != NULL) { ha_msg_mod_int(data, F_XML_PARENT, 1); } else { ha_msg_mod_int(data, F_XML_PARENT, 0); } } const char * crm_element_value(const crm_data_t *data, const char *name) { const char *value = NULL; crm_validate_data(data); value = cl_get_string(data, name); #if XML_PARANOIA_CHECKS - CRM_DEV_ASSERT(value == NULL || cl_is_allocated(value) == 1); + CRM_CHECK(value == NULL || cl_is_allocated(value) == 1, return NULL); #endif return value; } char * crm_element_value_copy(const crm_data_t *data, const char *name) { const char *value = NULL; char *value_copy = NULL; crm_validate_data(data); value = cl_get_string(data, name); #if XML_PARANOIA_CHECKS - CRM_DEV_ASSERT(cl_is_allocated(value) == 1); + CRM_CHECK(cl_is_allocated(value) == 1, return NULL); #endif if(value != NULL) { value_copy = crm_strdup(value); } return value_copy; } const char * crm_element_name(const crm_data_t *data) { #if CRM_DEV_BUILD crm_validate_data(data); #endif return cl_get_string(data, F_XML_TAGNAME); } void xml_remove_prop(crm_data_t *obj, const char *name) { if(crm_element_value(obj, name) != NULL) { cl_msg_remove(obj, name); } } void crm_update_parents(crm_data_t *xml_root) { crm_validate_data(xml_root); xml_child_iter( xml_root, a_child, crm_set_element_parent(a_child, xml_root); crm_update_parents(a_child); ); } int get_tag_name(const char *input) { int lpc = 0; char ch = 0; const char *error = NULL; gboolean do_special = FALSE; for(lpc = 0; error == NULL && lpc < (ssize_t)strlen(input); lpc++) { ch = input[lpc]; crm_debug_5("Processing char %c [%d]", ch, lpc); switch(ch) { case 0: error = "unexpected EOS"; break; case '?': if(lpc == 0) { /* weird xml tag that we dont care about */ do_special = TRUE; } else { return lpc; } break; case '/': case '>': case '\t': case '\n': case ' ': if(!do_special) { return lpc; } break; default: if(do_special) { } else if('a' <= ch && ch <= 'z') { } else if('A' <= ch && ch <= 'Z') { } else if(ch == '_') { } else if(ch == '-') { } else { error = "bad character, not in [a-zA-Z_-]"; } break; } } crm_err("Error parsing token near %.15s: %s", input, crm_str(error)); return -1; } int get_attr_name(const char *input) { int lpc = 0; char ch = 0; const char *error = NULL; for(lpc = 0; error == NULL && lpc < (ssize_t)strlen(input); lpc++) { ch = input[lpc]; crm_debug_5("Processing char %c[%d]", ch, lpc); switch(ch) { case 0: error = "unexpected EOS"; break; case '\t': case '\n': case ' ': error = "unexpected whitespace"; break; case '=': return lpc; default: if('a' <= ch && ch <= 'z') { } else if('A' <= ch && ch <= 'Z') { } else if(isdigit((int) ch)) { } else if(ch == '_') { } else if(ch == '-') { } else { error = "bad character, not in [a-zA-Z0-9_-]"; } break; } } crm_err("Error parsing token near %.15s: %s", input, crm_str(error)); return -1; } int get_attr_value(const char *input) { int lpc = 0; char ch = 0; const char *error = NULL; for(lpc = 0; error == NULL && lpc < (ssize_t)strlen(input); lpc++) { ch = input[lpc]; crm_debug_5("Processing char %c [%d]", ch, lpc); switch(ch) { case 0: error = "unexpected EOS"; break; case '\\': if(input[lpc+1] == '"') { /* skip over the next char */ lpc++; break; } /*fall through*/ case '"': return lpc; default: break; } } crm_err("Error parsing token near %.15s: %s", input, crm_str(error)); return -1; } int is_comment_start(const char *input) { - CRM_DEV_ASSERT(input != NULL); - if(crm_assert_failed) { - return 0; - } + CRM_CHECK(input != NULL, return 0); if(strlen(input) > 4 && input[0] == '<' && input[1] == '!' && input[2] == '-' && input[3] == '-') { crm_debug_6("Found comment start: "); return 3; } else if(strlen(input) > 1 && input[0] == '?' && input[1] == '>') { crm_debug_6("Found comment end: ?>"); return 2; } if(strlen(input) > 2) { crm_debug_6("Not comment end: %c%c%c", input[0], input[1], input[2]); } else { crm_debug_6("Not comment end"); } return 0; } gboolean drop_comments(const char *input, int *offset) { gboolean more = TRUE; gboolean in_directive = FALSE; int in_comment = FALSE; const char *our_input = input; int len = 0, lpc = 0; int tag_len = 0; char ch = 0; if(input == NULL) { return FALSE; } if(offset != NULL) { our_input = input + (*offset); } len = strlen(our_input); while(lpc < len && more) { ch = our_input[lpc]; crm_debug_6("Processing char %c[%d]", ch, lpc); switch(ch) { case 0: if(in_comment == FALSE) { more = FALSE; } else { crm_err("unexpected EOS"); crm_warn("Parsing error at or before: %s", our_input); } break; case '<': tag_len = is_comment_start(our_input + lpc); if(tag_len > 0) { if(in_comment) { crm_err("Nested XML comments are not supported!"); crm_warn("Parsing error at or before: %s", our_input); crm_warn("Netsed comment found at: %s", our_input + lpc + tag_len); } in_comment = TRUE; lpc+=tag_len; if(tag_len == 2) { #if 1 if(our_input[lpc-1] == '!') { in_directive = TRUE; } #else tag_len = get_tag_name(our_input + lpc); crm_debug_2("Tag length: %d", len); if(strncmp("DOCTYPE", our_input+lpc, tag_len) == 0) { in_directive = TRUE; } #endif } } else if(in_comment == FALSE){ more = FALSE; } else { lpc++; crm_debug_6("Skipping comment char %c", our_input[lpc]); } break; case '>': lpc++; if(in_directive) { in_directive = FALSE; in_comment = FALSE; } break; case '-': case '?': tag_len = is_comment_end(our_input + lpc); if(tag_len > 0) { lpc+=tag_len; in_comment = FALSE; } else { lpc++; crm_debug_6("Skipping comment char %c", our_input[lpc]); } break; case ' ': case '\t': case '\n': case '\r': lpc++; crm_debug_6("Skipping whitespace char %d", our_input[lpc]); break; default: lpc++; crm_debug_6("Skipping comment char %c", our_input[lpc]); break; } } crm_debug_4("Finished processing comments"); if(offset != NULL) { (*offset) += lpc; } if(lpc > 0) { crm_debug_5("Skipped %d comment chars", lpc); return TRUE; } return FALSE; } crm_data_t* parse_xml(const char *input, int *offset) { int len = 0, lpc = 0; char ch = 0; char *tag_name = NULL; char *attr_name = NULL; char *attr_value = NULL; gboolean more = TRUE; gboolean were_comments = TRUE; const char *error = NULL; const char *our_input = input; crm_data_t *new_obj = NULL; if(input == NULL) { return NULL; } if(offset != NULL) { our_input = input + (*offset); } len = strlen(our_input); while(lpc < len && were_comments) { were_comments = drop_comments(our_input, &lpc); } - CRM_DEV_ASSERT(our_input[lpc] == '<'); - if(crm_assert_failed) { - return NULL; - } + CRM_CHECK(our_input[lpc] == '<', return NULL); lpc++; len = get_tag_name(our_input + lpc); crm_debug_5("Tag length: %d", len); if(len < 0) { return NULL; } crm_malloc0(tag_name, len+1); strncpy(tag_name, our_input + lpc, len+1); tag_name[len] = EOS; crm_debug_4("Processing tag %s", tag_name); new_obj = ha_msg_new(1); ha_msg_add(new_obj, F_XML_TAGNAME, tag_name); lpc += len; for(; more && error == NULL && lpc < (ssize_t)strlen(input); lpc++) { ch = our_input[lpc]; crm_debug_5("Processing char %c[%d]", ch, lpc); switch(ch) { case 0: error = "unexpected EOS"; break; case '/': if(our_input[lpc+1] == '>') { more = FALSE; } break; case '<': if(our_input[lpc+1] != '/') { crm_data_t *child = NULL; gboolean any_comments = FALSE; do { were_comments = drop_comments(our_input, &lpc); any_comments = any_comments || were_comments; } while(lpc < len && were_comments); if(any_comments) { lpc--; break; } crm_debug_4("Start parsing child..."); child = parse_xml(our_input, &lpc); if(child == NULL) { error = "error parsing child"; } else { ha_msg_addstruct_compress( new_obj, crm_element_name(child), child); crm_debug_4("Finished parsing child: %s", crm_element_name(child)); ha_msg_del(child); if(our_input[lpc] == '<') { /* lpc is about to get incrimented * make sure we process the '<' that * we're currently looking at */ lpc--; } /* lpc++; /\* > *\/ */ } } else { lpc += 2; /* *\/ */ if(our_input[lpc] != '>') { error = "clase tag cannot contain attrs"; } crm_debug_4("Finished parsing ourselves: %s", crm_element_name(new_obj)); } else { error = "Mismatching close tag"; crm_err("Expected: %s", tag_name); } } break; case '=': lpc++; /* = */ /*fall through*/ case '"': lpc++; /* " */ len = get_attr_value(our_input+lpc); if(len < 0) { error = "couldnt find attr_value"; } else { crm_malloc0(attr_value, len+1); strncpy(attr_value, our_input+lpc, len+1); attr_value[len] = EOS; lpc += len; /* lpc++; /\* " *\/ */ crm_debug_4("creating nvpair: <%s %s=\"%s\"...", tag_name, crm_str(attr_name), crm_str(attr_value)); ha_msg_add(new_obj, attr_name, attr_value); crm_free(attr_name); crm_free(attr_value); } break; case '>': case ' ': case '\t': case '\n': case '\r': break; default: len = get_attr_name(our_input+lpc); if(len < 0) { error = "couldnt find attr_name"; } else { crm_malloc0(attr_name, len+1); strncpy(attr_name, our_input+lpc, len+1); attr_name[len] = EOS; lpc += len; crm_debug_4("found attr name: %s", attr_name); lpc--; /* make sure the '=' is seen next time around */ } break; } } if(error) { crm_err("Error parsing token: %s", error); crm_err("Error at or before: %s", our_input+lpc-3); return NULL; } crm_debug_4("Finished processing %s tag", tag_name); crm_free(tag_name); if(offset != NULL) { (*offset) += lpc; } return new_obj; } void log_xml_diff(unsigned int log_level, crm_data_t *diff, const char *function) { crm_data_t *added = find_xml_node(diff, "diff-added", FALSE); crm_data_t *removed = find_xml_node(diff, "diff-removed", FALSE); gboolean is_first = TRUE; xml_child_iter( removed, child, log_data_element(function, "-", log_level, 0, child, TRUE); if(is_first) { is_first = FALSE; } else { crm_log_maybe(log_level, " --- "); } ); /* crm_log_maybe(log_level, " === "); */ is_first = TRUE; xml_child_iter( added, child, log_data_element(function, "+", log_level, 0, child, TRUE); if(is_first) { is_first = FALSE; } else { crm_log_maybe(log_level, " --- "); } ); } gboolean apply_xml_diff(crm_data_t *old, crm_data_t *diff, crm_data_t **new) { gboolean result = TRUE; crm_data_t *added = find_xml_node(diff, "diff-added", FALSE); crm_data_t *removed = find_xml_node(diff, "diff-removed", FALSE); int root_nodes_seen = 0; - CRM_DEV_ASSERT(new != NULL); - if(crm_assert_failed) { return FALSE; } + CRM_CHECK(new != NULL, return FALSE); crm_debug_2("Substraction Phase"); xml_child_iter(removed, child_diff, - CRM_DEV_ASSERT(root_nodes_seen == 0); + CRM_CHECK(root_nodes_seen == 0, result = FALSE); if(root_nodes_seen == 0) { *new = subtract_xml_object(old, child_diff, FALSE); } root_nodes_seen++; ); if(root_nodes_seen == 0) { *new = copy_xml(old); } else if(root_nodes_seen > 1) { crm_err("(-) Diffs cannot contain more than one change set..." " saw %d", root_nodes_seen); result = FALSE; } root_nodes_seen = 0; crm_debug_2("Addition Phase"); if(result) { xml_child_iter(added, child_diff, - CRM_DEV_ASSERT(root_nodes_seen == 0); + CRM_CHECK(root_nodes_seen == 0, result = FALSE); if(root_nodes_seen == 0) { add_xml_object(NULL, *new, child_diff); } root_nodes_seen++; ); } if(root_nodes_seen > 1) { crm_err("(+) Diffs cannot contain more than one change set..." " saw %d", root_nodes_seen); result = FALSE; #if CRM_DEV_BUILD } else if(result) { crm_data_t *intermediate = NULL; crm_data_t *diff_of_diff = NULL; crm_debug_2("Verification Phase"); intermediate = diff_xml_object(old, *new, FALSE); diff_of_diff = diff_xml_object(intermediate, diff, TRUE); if(diff_of_diff != NULL) { crm_warn("Diff application failed!"); /* log_xml_diff(LOG_DEBUG, diff_of_diff, "diff:diff_of_diff"); */ log_xml_diff(LOG_INFO, intermediate, "diff:actual_diff"); result = FALSE; } free_xml(diff_of_diff); free_xml(intermediate); diff_of_diff = NULL; intermediate = NULL; #endif } if(result == FALSE) { log_xml_diff(LOG_INFO, diff, "diff:input_diff"); log_data_element("diff:input", NULL, LOG_DEBUG_2, 0, old, TRUE); -/* CRM_DEV_ASSERT(diff_of_diff != NULL); */ +/* CRM_CHECK(diff_of_diff != NULL); */ result = FALSE; } return result; } crm_data_t * diff_xml_object(crm_data_t *old, crm_data_t *new, gboolean suppress) { crm_data_t *diff = NULL; crm_data_t *tmp1 = NULL; crm_data_t *added = NULL; crm_data_t *removed = NULL; tmp1 = subtract_xml_object(old, new, suppress); if(tmp1 != NULL) { diff = create_xml_node(NULL, "diff"); /* if(can_prune_leaf(tmp1)) { ha_msg_del(tmp1); tmp1 = NULL; } else { */ removed = create_xml_node(diff, "diff-removed"); added = create_xml_node(diff, "diff-added"); add_node_copy(removed, tmp1); free_xml(tmp1); } tmp1 = subtract_xml_object(new, old, suppress); if(tmp1 != NULL) { /* never filter added nodes */ if(diff == NULL) { diff = create_xml_node(NULL, "diff"); } if(removed == NULL) { removed = create_xml_node(diff, "diff-removed"); } if(added == NULL) { added = create_xml_node(diff, "diff-added"); } add_node_copy(added, tmp1); free_xml(tmp1); } return diff; } gboolean can_prune_leaf(crm_data_t *xml_node) { gboolean can_prune = TRUE; /* return FALSE; */ xml_prop_iter(xml_node, prop_name, prop_value, if(safe_str_eq(prop_name, XML_ATTR_ID)) { continue; } else if(safe_str_eq(prop_name, XML_ATTR_TSTAMP)) { continue; } can_prune = FALSE; ); xml_child_iter(xml_node, child, if(can_prune_leaf(child)) { cl_msg_remove_value(xml_node, child); __counter--; } else { can_prune = FALSE; } ); return can_prune; } void diff_filter_context(int context, int upper_bound, int lower_bound, crm_data_t *xml_node, crm_data_t *parent) { crm_data_t *us = NULL; crm_data_t *new_parent = parent; const char *name = crm_element_name(xml_node); - CRM_DEV_ASSERT(xml_node != NULL && name != NULL); - if(crm_assert_failed) { return; } + CRM_CHECK(xml_node != NULL && name != NULL, return); us = create_xml_node(parent, name); xml_prop_iter(xml_node, prop_name, prop_value, lower_bound = context; crm_xml_add(us, prop_name, prop_value); ); if(lower_bound >= 0 || upper_bound >= 0) { crm_xml_add(us, XML_ATTR_ID, ID(xml_node)); new_parent = us; } else { upper_bound = in_upper_context(0, context, xml_node); if(upper_bound >= 0) { crm_xml_add(us, XML_ATTR_ID, ID(xml_node)); new_parent = us; } else { free_xml(us); us = NULL; } } xml_child_iter(us, child, diff_filter_context( context, upper_bound-1, lower_bound-1, child, new_parent); ); } int in_upper_context(int depth, int context, crm_data_t *xml_node) { gboolean has_attributes = FALSE; if(context == 0) { return 0; } xml_prop_iter(xml_node, prop_name, prop_value, has_attributes = TRUE; break; ); if(has_attributes) { return depth; } else if(depth < context) { xml_child_iter(xml_node, child, if(in_upper_context(depth+1, context, child)) { return depth; } ); } return 0; } crm_data_t * subtract_xml_object(crm_data_t *left, crm_data_t *right, gboolean suppress) { gboolean skip = FALSE; gboolean differences = FALSE; crm_data_t *diff = NULL; crm_data_t *child_diff = NULL; crm_data_t *right_child = NULL; const char *right_val = NULL; const char *name = NULL; int lpc = 0; const char *filter[] = { XML_ATTR_TSTAMP, "last_written", "debug_source", "origin", "te-allow-fail" }; if(left == NULL) { return NULL; } else if(right == NULL) { crm_debug_5("Processing <%s id=%s> (complete copy)", crm_element_name(left), ID(left)); return copy_xml(left); } name = crm_element_name(left); /* sanity check */ - CRM_DEV_ASSERT(name != NULL); - if(crm_assert_failed) { return NULL; } + CRM_CHECK(name != NULL, return NULL); - CRM_DEV_ASSERT(safe_str_eq(crm_element_name(left), - crm_element_name(right))); - if(crm_assert_failed) { return NULL; } + CRM_CHECK(safe_str_eq(crm_element_name(left), + crm_element_name(right)), return NULL); - CRM_DEV_ASSERT(safe_str_eq(ID(left), ID(right))); - if(crm_assert_failed) { return NULL; } + CRM_CHECK(safe_str_eq(ID(left), ID(right)), return NULL); diff = create_xml_node(NULL, name); /* changes to name/value pairs */ crm_debug_5("Processing <%s id=%s>", crm_str(name), ID(left)); xml_prop_iter(left, prop_name, left_value, skip = FALSE; if(safe_str_eq(prop_name, XML_ATTR_ID)) { skip = TRUE; } for(lpc = 0; skip == FALSE && suppress && lpc < DIMOF(filter); lpc++) { if(safe_str_eq(prop_name, filter[lpc])) { skip = TRUE; } } if(skip) { continue; } right_val = crm_element_value(right, prop_name); if(right_val == NULL) { differences = TRUE; crm_xml_add(diff, prop_name, left_value); crm_debug_6("\t%s: %s", crm_str(prop_name), crm_str(left_value)); } else if(safe_str_eq(left_value, right_val)) { crm_debug_5("\t%s: %s (removed)", crm_str(prop_name), crm_str(left_value)); } else { differences = TRUE; crm_xml_add(diff, prop_name, left_value); crm_debug_5("\t%s: %s->%s", crm_str(prop_name), crm_str(left_value), right_val); } ); /* changes to child objects */ xml_child_iter( left, left_child, right_child = find_entity( right, crm_element_name(left_child), ID(left_child)); child_diff = subtract_xml_object( left_child, right_child, suppress); if(child_diff != NULL) { differences = TRUE; add_node_copy(diff, child_diff); free_xml(child_diff); } ); if(differences == FALSE) { free_xml(diff); crm_debug_5("\tNo changes"); return NULL; } crm_xml_add(diff, XML_ATTR_ID, ID(left)); return diff; } int add_xml_object(crm_data_t *parent, crm_data_t *target, const crm_data_t *update) { const char *object_id = NULL; const char *object_name = NULL; const char *right_val = NULL; int result = 0; - CRM_DEV_ASSERT(update != NULL); - if(crm_assert_failed) { return 0; } + CRM_CHECK(update != NULL, return 0); object_name = crm_element_name(update); object_id = ID(update); - CRM_DEV_ASSERT(object_name != NULL); - if(crm_assert_failed) { return 0; } + CRM_CHECK(object_name != NULL, return 0); if(target == NULL && object_id == NULL) { /* placeholder object */ target = find_xml_node(parent, object_name, FALSE); } else if(target == NULL) { target = find_entity(parent, object_name, object_id); } if(target == NULL) { target = add_node_copy(parent, update); crm_debug_2("Added <%s id=%s>", crm_str(object_name), crm_str(object_id)); - CRM_DEV_ASSERT(target != NULL); - return 0; - + CRM_CHECK(target != NULL, return 0); } crm_debug_2("Found node <%s id=%s> to update", crm_str(object_name), crm_str(object_id)); xml_prop_iter(update, prop_name, left_value, right_val = crm_element_value(target, prop_name); if(right_val == NULL) { crm_xml_add(target, prop_name, left_value); crm_debug_2("\t%s: %s (added)", crm_str(prop_name), crm_str(left_value)); } else if(safe_str_neq(left_value, right_val)) { crm_xml_add(target, prop_name, left_value); crm_debug_2("\t%s: %s->%s", crm_str(prop_name), crm_str(left_value), right_val); } ); crm_debug_3("Processing children of <%s id=%s>", crm_str(object_name), crm_str(object_id)); xml_child_iter( update, a_child, int tmp_result = 0; crm_debug_3("Updating child <%s id=%s>", crm_element_name(a_child), ID(a_child)); tmp_result = add_xml_object(target, NULL, a_child); if(tmp_result < 0) { crm_err("Error updating child <%s id=%s>", crm_element_name(a_child), ID(a_child)); /* only the first error is likely to be interesting */ if(result >= 0) { result = tmp_result; } } ); crm_debug_3("Finished with <%s id=%s>", crm_str(object_name), crm_str(object_id)); return result; } gboolean update_xml_child(crm_data_t *child, crm_data_t *to_update) { gboolean can_update = TRUE; - CRM_DEV_ASSERT(child != NULL); - if(crm_assert_failed) { return FALSE; } - - CRM_DEV_ASSERT(to_update != NULL); - if(crm_assert_failed) { return FALSE; } + CRM_CHECK(child != NULL, return FALSE); + CRM_CHECK(to_update != NULL, return FALSE); if(safe_str_neq(crm_element_name(to_update), crm_element_name(child))) { can_update = FALSE; } else if(safe_str_neq(ID(to_update), ID(child))) { can_update = FALSE; } else if(can_update) { crm_log_xml_debug(child, "Update match found..."); copy_in_properties(child, to_update); } xml_child_iter( child, child_of_child, /* only update the first one */ if(can_update) { break; } can_update = update_xml_child(child_of_child, to_update); ); return can_update; } gboolean find_xml_child(crm_data_t *child, const char *tag, const char *id) { gboolean match_found = TRUE; - CRM_DEV_ASSERT(child != NULL); - if(crm_assert_failed) { return FALSE; } + CRM_CHECK(child != NULL, return FALSE); if(safe_str_neq(tag, crm_element_name(child))) { match_found = FALSE; } else if(safe_str_neq(id, ID(child))) { match_found = FALSE; } else if(match_found) { crm_err("Update match found for <%s id=%s.../>", tag, id); crm_log_xml_debug(child, __FUNCTION__); } xml_child_iter( child, child_of_child, /* only find the first one */ if(match_found) { break; } match_found = find_xml_child(child_of_child, tag, id); ); return match_found; } gboolean delete_xml_child(crm_data_t *parent, crm_data_t *child, crm_data_t *to_delete) { gboolean can_delete = FALSE; const char *right_val = NULL; - CRM_DEV_ASSERT(child != NULL); - if(crm_assert_failed) { return FALSE; } - - CRM_DEV_ASSERT(to_delete != NULL); - if(crm_assert_failed) { return FALSE; } + CRM_CHECK(child != NULL, return FALSE); + CRM_CHECK(to_delete != NULL, return FALSE); if(safe_str_eq(crm_element_name(to_delete), crm_element_name(child))) { can_delete = TRUE; } xml_prop_iter(to_delete, prop_name, left_value, if(can_delete == FALSE) { break; } right_val = crm_element_value(child, prop_name); if(safe_str_neq(left_value, right_val)) { can_delete = FALSE; } ); if(can_delete && parent != NULL) { crm_log_xml_debug(child, "Delete match found..."); cl_msg_remove_value(parent, child); child = NULL; } else if(can_delete) { crm_log_xml_debug(child, "Cannot delete the search root"); } xml_child_iter( child, child_of_child, /* only delete the first one */ if(can_delete) { break; } can_delete = delete_xml_child(child, child_of_child, to_delete); ); return can_delete; } 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_ATTR_ID, name); 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); } void hash2field(gpointer key, gpointer value, gpointer user_data) { const char *name = key; const char *s_value = value; crm_data_t *xml_node = user_data; if(crm_element_value(xml_node, name) == NULL) { crm_xml_add(xml_node, name, s_value); crm_debug_3("dumped: %s=%s", name, s_value); } else { crm_debug_2("duplicate: %s=%s", name, s_value); } } #if CRM_DEPRECATED_SINCE_2_0_3 GHashTable * xml2list_202(crm_data_t *parent) { crm_data_t *nvpair_list = NULL; GHashTable *nvpair_hash = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); - CRM_DEV_ASSERT(parent != NULL); - if(parent != NULL) { - nvpair_list = find_xml_node(parent, XML_TAG_ATTRS, FALSE); - if(nvpair_list == NULL) { - crm_debug("No attributes in %s", - crm_element_name(parent)); - crm_log_xml_debug_2( - parent,"No attributes for resource op"); - } + CRM_CHECK(parent != NULL, return nvpair_hash); + + nvpair_list = find_xml_node(parent, XML_TAG_ATTRS, FALSE); + if(nvpair_list == NULL) { + crm_debug("No attributes in %s", + crm_element_name(parent)); + crm_log_xml_debug_2( + parent,"No attributes for resource op"); } xml_child_iter_filter( nvpair_list, node_iter, XML_CIB_TAG_NVPAIR, const char *key = crm_element_value( node_iter, XML_NVPAIR_ATTR_NAME); const char *value = crm_element_value( node_iter, XML_NVPAIR_ATTR_VALUE); crm_debug_2("Added %s=%s", key, value); g_hash_table_insert( nvpair_hash, crm_strdup(key), crm_strdup(value)); ); return nvpair_hash; } #endif GHashTable * xml2list(crm_data_t *parent) { crm_data_t *nvpair_list = NULL; GHashTable *nvpair_hash = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); - CRM_DEV_ASSERT(parent != NULL); - if(parent != NULL) { - nvpair_list = find_xml_node(parent, XML_TAG_ATTRS, FALSE); - if(nvpair_list == NULL) { - crm_debug_2("No attributes in %s", - crm_element_name(parent)); - crm_log_xml_debug_2( - parent,"No attributes for resource op"); - } + CRM_CHECK(parent != NULL, return nvpair_hash); + + nvpair_list = find_xml_node(parent, XML_TAG_ATTRS, FALSE); + if(nvpair_list == NULL) { + crm_debug_2("No attributes in %s", + crm_element_name(parent)); + crm_log_xml_debug_2( + parent,"No attributes for resource op"); } crm_log_xml_debug_3(nvpair_list, "Unpacking"); xml_prop_iter( nvpair_list, key, value, crm_debug_2("Added %s=%s", key, value); g_hash_table_insert( nvpair_hash, crm_strdup(key), crm_strdup(value)); ); return nvpair_hash; } static void assign_uuid(crm_data_t *xml_obj) { cl_uuid_t new_uuid; char *new_uuid_s = NULL; const char *tag_name = crm_element_name(xml_obj); const char *tag_id = ID(xml_obj); crm_malloc0(new_uuid_s, sizeof(char)*38); cl_uuid_generate(&new_uuid); cl_uuid_unparse(&new_uuid, new_uuid_s); crm_warn("Updating object from <%s id=%s/> to <%s id=%s/>", tag_name, tag_id?tag_id:"__empty__", tag_name, new_uuid_s); crm_xml_add(xml_obj, XML_ATTR_ID, new_uuid_s); crm_log_xml_debug(xml_obj, "Updated object"); crm_free(new_uuid_s); } gboolean do_id_check(crm_data_t *xml_obj, GHashTable *id_hash) { int lpc = 0; char *lookup_id = NULL; gboolean modified = FALSE; const char *tag_id = NULL; const char *tag_name = NULL; const char *lookup_value = NULL; gboolean created_hash = FALSE; const char *allowed_list[] = { XML_TAG_CIB, XML_TAG_FRAGMENT, XML_CIB_TAG_NODES, XML_CIB_TAG_RESOURCES, XML_CIB_TAG_CONSTRAINTS, XML_CIB_TAG_STATUS, XML_CIB_TAG_LRM, XML_LRM_TAG_RESOURCES, XML_TAG_PARAMS, "operations", }; const char *non_unique[] = { XML_LRM_TAG_RESOURCE, XML_LRM_TAG_RSC_OP, }; if(xml_obj == NULL) { return FALSE; } else if(id_hash == NULL) { created_hash = TRUE; id_hash = g_hash_table_new_full( g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str); } xml_child_iter( xml_obj, xml_child, if(do_id_check(xml_child, id_hash)) { modified = TRUE; } ); tag_id = ID(xml_obj); tag_name = TYPE(xml_obj); xml_prop_iter( xml_obj, local_prop_name, local_prop_value, lookup_id = NULL; if(ID(xml_obj) != NULL) { for(lpc = 0; lpc < DIMOF(non_unique); lpc++) { if(safe_str_eq(tag_name, non_unique[lpc])) { /* this tag is never meant to have an ID */ break; } } if(lpc < DIMOF(non_unique)) { break; } lookup_id = crm_concat(tag_name, tag_id, '-'); lookup_value = g_hash_table_lookup(id_hash, lookup_id); if(lookup_value != NULL) { char *old_id = crm_strdup(tag_id); modified = TRUE; assign_uuid(xml_obj); tag_id = ID(xml_obj); crm_err("\"id\" collision detected..." " Multiple '%s' entries with id=\"%s\"," " assigned id=\"%s\"", tag_name, old_id, tag_id); } g_hash_table_insert( id_hash, lookup_id, crm_strdup(tag_id)); break; } for(lpc = 0; lpc < DIMOF(allowed_list); lpc++) { if(safe_str_eq(tag_name, allowed_list[lpc])) { /* this tag is never meant to have an ID */ break; } } if(lpc < DIMOF(allowed_list)) { break; } modified = TRUE; crm_err("%s object with attributes but no ID field detected.", tag_name); assign_uuid(xml_obj); break; ); if(created_hash) { g_hash_table_destroy(id_hash); } return modified; } diff --git a/lib/crm/transition/actions.c b/lib/crm/transition/actions.c index 1d8dc76ee5..64833ae14f 100644 --- a/lib/crm/transition/actions.c +++ b/lib/crm/transition/actions.c @@ -1,449 +1,449 @@ -/* $Id: actions.c,v 1.1 2006/02/14 11:32:12 andrew Exp $ */ +/* $Id: actions.c,v 1.2 2006/03/18 17:23:49 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 gboolean initiate_action(action_t *action); void cib_action_updated( const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data); static void cib_fencing_updated(const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data) { if(rc < cib_ok) { crm_err("CIB update failed: %s", cib_error2string(rc)); crm_log_xml_warn(msg, "[Failed Update]"); } check_for_completion(); } void send_stonith_update(stonith_ops_t * op) { enum cib_errors rc = cib_ok; const char *target = op->node_name; const char *uuid = op->node_uuid; /* zero out the node-status & remove all LRM status info */ crm_data_t *update = NULL; crm_data_t *node_state = create_xml_node(NULL, XML_CIB_TAG_STATE); - CRM_DEV_ASSERT(op->node_name != NULL); - CRM_DEV_ASSERT(op->node_uuid != NULL); + CRM_CHECK(op->node_name != NULL); + CRM_CHECK(op->node_uuid != NULL); crm_xml_add(node_state, XML_ATTR_UUID, uuid); crm_xml_add(node_state, XML_ATTR_UNAME, target); crm_xml_add(node_state, XML_CIB_ATTR_HASTATE, DEADSTATUS); crm_xml_add(node_state, XML_CIB_ATTR_INCCM, XML_BOOLEAN_NO); crm_xml_add(node_state, XML_CIB_ATTR_CRMDSTATE, OFFLINESTATUS); crm_xml_add(node_state, XML_CIB_ATTR_JOINSTATE, CRMD_JOINSTATE_DOWN); crm_xml_add(node_state, XML_CIB_ATTR_EXPSTATE, CRMD_JOINSTATE_DOWN); crm_xml_add(node_state, XML_CIB_ATTR_REPLACE, XML_CIB_TAG_LRM); create_xml_node(node_state, XML_CIB_TAG_LRM); update = create_cib_fragment(node_state, XML_CIB_TAG_STATUS); rc = te_cib_conn->cmds->update( te_cib_conn, XML_CIB_TAG_STATUS, update, NULL, cib_quorum_override|cib_scope_local); if(rc < cib_ok) { const char *fail_text = "Couldnt update CIB after stonith"; crm_err("CIB update failed: %s", cib_error2string(rc)); send_complete(fail_text, update, te_failed, i_cancel); } else { /* delay processing the trigger until the update completes */ add_cib_op_callback(rc, FALSE, NULL, cib_fencing_updated); } free_xml(node_state); free_xml(update); return; } static gboolean te_fence_node(action_t *action) { char *key = NULL; const char *id = NULL; const char *uuid = NULL; const char *target = NULL; stonith_ops_t * st_op = NULL; id = ID(action->xml); target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); uuid = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID); - CRM_DEV_ASSERT(id != NULL); - CRM_DEV_ASSERT(uuid != NULL); - CRM_DEV_ASSERT(target != NULL); + CRM_CHECK(id != NULL); + CRM_CHECK(uuid != NULL); + CRM_CHECK(target != NULL); if(crm_assert_failed) { /* error */ te_log_action(LOG_ERR, "Corrupted command (id=%s): no node", crm_str(id)); return FALSE; } te_log_action(LOG_INFO, "Executing fencing operation (%s) on %s (timeout=%d)", id, target, transition_idle_timeout / 2); #ifdef TESTING action->complete = TRUE; process_trigger(action->id); return TRUE; #endif crm_malloc0(st_op, sizeof(stonith_ops_t)); st_op->optype = RESET; st_op->timeout = transition_idle_timeout / 2; st_op->node_name = crm_strdup(target); st_op->node_uuid = crm_strdup(uuid); key = generate_transition_key(transition_counter, te_uuid); st_op->private_data = crm_concat(id, key, ';'); crm_free(key); if(stonithd_input_IPC_channel() == NULL) { crm_err("Cannot fence %s: stonith not available", target); return FALSE; } else if (ST_OK != stonithd_node_fence( st_op )) { crm_err("Cannot fence %s: stonithd_node_fence() call failed ", target); return FALSE; } stop_te_timer(transition_timer); start_te_timer(transition_timer); return TRUE; } static gboolean te_crm_command(action_t *action) { char *value = NULL; char *counter = NULL; HA_Message *cmd = NULL; const char *id = NULL; const char *task = NULL; const char *on_node = NULL; gboolean ret = TRUE; id = ID(action->xml); task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); on_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); - CRM_DEV_ASSERT(on_node != NULL && strlen(on_node) != 0); + CRM_CHECK(on_node != NULL && strlen(on_node) != 0); if(crm_assert_failed) { /* error */ te_log_action(LOG_ERR, "Corrupted command (id=%s) %s: no node", crm_str(id), crm_str(task)); return FALSE; } te_log_action(LOG_INFO, "Executing crm-event (%s): %s on %s", crm_str(id), crm_str(task), on_node); #ifdef TESTING action->complete = TRUE; process_trigger(action->id); return TRUE; #endif cmd = create_request(task, NULL, on_node, CRM_SYSTEM_CRMD, CRM_SYSTEM_TENGINE, NULL); counter = generate_transition_key(transition_counter, te_uuid); crm_xml_add(cmd, XML_ATTR_TRANSITION_KEY, counter); ret = send_ipc_message(crm_ch, cmd); crm_free(counter); value = g_hash_table_lookup(action->params, XML_ATTR_TE_NOWAIT); if(ret == FALSE) { crm_err("Action %d failed: send", action->id); return FALSE; } else if(crm_is_true(value)) { crm_info("Skipping wait for %d", action->id); action->complete = TRUE; process_trigger(action->id); } else if(ret && action->timeout > 0) { crm_debug_3("Setting timer for action %d",action->id); action->timer->reason = timeout_action_warn; start_te_timer(action->timer); } return TRUE; } static gboolean te_rsc_command(action_t *action) { /* never overwrite stop actions in the CIB with * anything other than completed results * * Writing pending stops makes it look like the * resource is running again */ const char *task = NULL; const char *on_node = NULL; action->invoked = FALSE; on_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); - CRM_DEV_ASSERT(on_node != NULL && strlen(on_node) != 0); + CRM_CHECK(on_node != NULL && strlen(on_node) != 0); if(crm_assert_failed) { /* error */ te_log_action(LOG_ERR, "Corrupted command(id=%s) %s: no node", ID(action->xml), crm_str(task)); return FALSE; } #ifdef TESTING cib_action_update(action, LRM_OP_DONE); return TRUE; #endif cib_action_updated(NULL, 0, cib_ok, NULL, action); return TRUE; } gboolean cib_action_update(action_t *action, int status) { char *code = NULL; crm_data_t *fragment = NULL; crm_data_t *state = NULL; crm_data_t *rsc = NULL; crm_data_t *xml_op = NULL; char *op_id = NULL; enum cib_errors rc = cib_ok; const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); const char *rsc_id = crm_element_value(action->xml, XML_LRM_ATTR_RSCID); const char *target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); const char *task_uuid = crm_element_value( action->xml, XML_LRM_ATTR_TASK_KEY); const char *target_uuid = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID); int call_options = cib_quorum_override|cib_scope_local; if(status == LRM_OP_TIMEOUT) { if(crm_element_value(action->xml, XML_LRM_ATTR_RSCID) != NULL) { crm_warn("%s: %s %s on %s timed out", crm_element_name(action->xml), task_uuid, rsc_id, target); } else { crm_warn("%s: %s on %s timed out", crm_element_name(action->xml), task_uuid, target); } } code = crm_itoa(status); /* update the CIB */ fragment = NULL; state = create_xml_node(NULL, XML_CIB_TAG_STATE); crm_xml_add(state, XML_ATTR_UUID, target_uuid); crm_xml_add(state, XML_ATTR_UNAME, target); rsc = create_xml_node(state, XML_CIB_TAG_LRM); rsc = create_xml_node(rsc, XML_LRM_TAG_RESOURCES); rsc = create_xml_node(rsc, XML_LRM_TAG_RESOURCE); xml_op = create_xml_node(rsc,XML_LRM_TAG_RSC_OP); crm_xml_add(rsc, XML_ATTR_ID, rsc_id); crm_xml_add(xml_op, XML_ATTR_ID, task); op_id = generate_op_key(rsc_id, task, action->interval); crm_xml_add(xml_op, XML_ATTR_ID, op_id); crm_free(op_id); crm_xml_add(xml_op, XML_LRM_ATTR_TASK, task); crm_xml_add(rsc, XML_LRM_ATTR_RSCSTATE, get_rsc_state(task, status)); crm_xml_add(xml_op, XML_LRM_ATTR_OPSTATUS, code); crm_xml_add(xml_op, XML_LRM_ATTR_CALLID, "-1"); crm_xml_add(xml_op, XML_LRM_ATTR_RC, code); crm_xml_add(xml_op, "origin", __FUNCTION__); crm_free(code); code = generate_transition_key(transition_counter, te_uuid); crm_xml_add(xml_op, XML_ATTR_TRANSITION_KEY, code); crm_free(code); code = generate_transition_magic( crm_element_value(xml_op, XML_ATTR_TRANSITION_KEY), status, status); crm_xml_add(xml_op, XML_ATTR_TRANSITION_MAGIC, code); crm_free(code); set_node_tstamp(xml_op); fragment = create_cib_fragment(state, XML_CIB_TAG_STATUS); crm_debug_3("Updating CIB with \"%s\" (%s): %s %s on %s", status<0?"new action":XML_ATTR_TIMEOUT, crm_element_name(action->xml), crm_str(task), rsc_id, target); #ifndef TESTING rc = te_cib_conn->cmds->update( te_cib_conn, XML_CIB_TAG_STATUS, fragment, NULL, call_options); crm_debug("Updating CIB with %s action %d: %s %s on %s (call_id=%d)", op_status2text(status), action->id, task_uuid, rsc_id, target, rc); if(status == LRM_OP_PENDING) { crm_debug_2("Waiting for callback id: %d", rc); add_cib_op_callback(rc, FALSE, action, cib_action_updated); } #else te_log_action(LOG_INFO, "Initiating action %d: %s %s on %s", action->id, task_uuid, rsc_id, target); call_options = 0; { HA_Message *cmd = ha_msg_new(11); ha_msg_add(cmd, F_TYPE, T_CRM); ha_msg_add(cmd, F_CRM_VERSION, CRM_FEATURE_SET); ha_msg_add(cmd, F_CRM_MSG_TYPE, XML_ATTR_REQUEST); ha_msg_add(cmd, F_CRM_TASK, CRM_OP_EVENTCC); ha_msg_add(cmd, F_CRM_SYS_TO, CRM_SYSTEM_TENGINE); ha_msg_add(cmd, F_CRM_SYS_FROM, CRM_SYSTEM_TENGINE); ha_msg_addstruct(cmd, crm_element_name(state), state); send_ipc_message(crm_ch, cmd); } #endif free_xml(fragment); free_xml(state); action->sent_update = TRUE; if(rc < cib_ok) { return FALSE; } return TRUE; } void cib_action_updated( const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data) { HA_Message *cmd = NULL; crm_data_t *rsc_op = NULL; action_t *action = user_data; char *counter = crm_itoa(transition_counter); const char *task = NULL; const char *value = NULL; const char *rsc_id = NULL; const char *on_node = NULL; const char *task_uuid = NULL; - CRM_DEV_ASSERT(action != NULL); if(crm_assert_failed) { return; } - CRM_DEV_ASSERT(action->xml != NULL); if(crm_assert_failed) { return; } + CRM_CHECK(action != NULL); if(crm_assert_failed) { return; } + CRM_CHECK(action->xml != NULL); if(crm_assert_failed) { return; } rsc_op = action->xml; task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); task_uuid = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY); rsc_id = crm_element_value(rsc_op, XML_LRM_ATTR_RSCID); on_node = crm_element_value(rsc_op, XML_LRM_ATTR_TARGET); counter = generate_transition_key(transition_counter, te_uuid); crm_xml_add(rsc_op, XML_ATTR_TRANSITION_KEY, counter); crm_free(counter); if(rc < cib_ok) { crm_err("Update for action %d: %s %s on %s FAILED", action->id, task_uuid, rsc_id, on_node); send_complete(cib_error2string(rc), output, te_failed, i_cancel); return; } if(te_fsa_state != s_in_transition) { int pending_updates = num_cib_op_callbacks(); if(pending_updates == 0) { send_complete("CIB update queue empty", output, te_done, i_cib_complete); } else { crm_debug("Still waiting on %d callbacks", pending_updates); } crm_debug("Not executing action: Not in a transition: %d", te_fsa_state); return; } crm_info("Initiating action %d: %s on %s", action->id, task_uuid, on_node); if(rsc_op != NULL) { crm_log_xml_debug_2(rsc_op, "Performing"); } cmd = create_request(CRM_OP_INVOKE_LRM, rsc_op, on_node, CRM_SYSTEM_LRMD, CRM_SYSTEM_TENGINE, NULL); #ifndef TESTING send_ipc_message(crm_ch, cmd); #else crm_log_message(LOG_INFO, cmd); #endif action->invoked = TRUE; value = g_hash_table_lookup(action->params, XML_ATTR_TE_NOWAIT); if(crm_is_true(value)) { crm_debug("Skipping wait for %d", action->id); action->complete = TRUE; process_trigger(action->id); } else if(action->timeout > 0) { crm_debug_3("Setting timer for action %s", task_uuid); action->timer->reason = timeout_action_warn; start_te_timer(action->timer); } } diff --git a/lib/crm/transition/graph.c b/lib/crm/transition/graph.c index 750a467845..871b786949 100644 --- a/lib/crm/transition/graph.c +++ b/lib/crm/transition/graph.c @@ -1,324 +1,317 @@ -/* $Id: graph.c,v 1.7 2006/03/17 00:42:16 andrew Exp $ */ +/* $Id: graph.c,v 1.8 2006/03/18 17:23:49 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 */ crm_graph_functions_t *graph_fns = NULL; static gboolean update_synapse_ready(synapse_t *synapse, int action_id) { gboolean updates = FALSE; - CRM_DEV_ASSERT(synapse->executed == FALSE); - CRM_DEV_ASSERT(synapse->confirmed == FALSE); + CRM_CHECK(synapse->executed == FALSE, return FALSE); + CRM_CHECK(synapse->confirmed == FALSE, return FALSE); synapse->ready = TRUE; slist_iter( prereq, crm_action_t, synapse->inputs, lpc, crm_debug_3("Processing input %d", prereq->id); if(prereq->id == action_id) { crm_debug_2("Marking input %d of synapse %d confirmed", action_id, synapse->id); prereq->confirmed = TRUE; updates = TRUE; } else if(prereq->confirmed == FALSE) { synapse->ready = FALSE; } ); if(updates) { crm_debug_2("Updated synapse %d", synapse->id); } return updates; } static gboolean update_synapse_confirmed(synapse_t *synapse, int action_id) { gboolean updates = FALSE; gboolean is_confirmed = TRUE; - CRM_DEV_ASSERT(synapse->executed); - CRM_DEV_ASSERT(synapse->confirmed == FALSE); + CRM_CHECK(synapse->executed, return FALSE); + CRM_CHECK(synapse->confirmed == FALSE, return TRUE); is_confirmed = TRUE; slist_iter( action, crm_action_t, synapse->actions, lpc, crm_debug_3("Processing action %d", action->id); if(action->id == action_id) { crm_info("Confirmed: Action %d of Synapse %d", action_id, synapse->id); action->confirmed = TRUE; updates = TRUE; } else if(action->confirmed == FALSE) { is_confirmed = FALSE; crm_debug_2("Synapse %d still not confirmed after action %d", synapse->id, action_id); } ); if(is_confirmed && synapse->confirmed == FALSE) { crm_debug("Confirmed: Synapse %d", synapse->id); synapse->confirmed = TRUE; updates = TRUE; } if(updates) { crm_debug_2("Updated synapse %d", synapse->id); } return updates; } gboolean update_graph(crm_graph_t *graph, crm_action_t *action) { gboolean rc = FALSE; gboolean updates = FALSE; slist_iter( synapse, synapse_t, graph->synapses, lpc, if (synapse->confirmed) { crm_debug_2("Synapse complete"); } else if (synapse->executed) { crm_debug_2("Synapse executed"); rc = update_synapse_confirmed(synapse, action->id); } else if(action->failed == FALSE) { rc = update_synapse_ready(synapse, action->id); } updates = updates || rc; ); if(updates) { crm_debug_2("Updated graph with completed action %d", action->id); } return updates; } static gboolean should_fire_synapse(synapse_t *synapse) { - CRM_DEV_ASSERT(synapse->executed == FALSE); - CRM_DEV_ASSERT(synapse->confirmed == FALSE); + CRM_CHECK(synapse->executed == FALSE, return FALSE); + CRM_CHECK(synapse->confirmed == FALSE, return FALSE); crm_debug_3("Checking pre-reqs for %d", synapse->id); /* lookup prereqs */ synapse->ready = TRUE; slist_iter( prereq, crm_action_t, synapse->inputs, lpc, crm_debug_3("Processing input %d", prereq->id); if(prereq->confirmed == FALSE) { crm_debug_3("Inputs for synapse %d not satisfied", synapse->id); synapse->ready = FALSE; break; } ); return synapse->ready; } static gboolean initiate_action(crm_graph_t *graph, crm_action_t *action) { const char *id = NULL; int tmp_time = 2 * action->timeout; - CRM_DEV_ASSERT(action->executed == FALSE); - if(crm_assert_failed) { - return FALSE; - } + CRM_CHECK(action->executed == FALSE, return FALSE); id = ID(action->xml); - CRM_DEV_ASSERT(id != NULL); - if(crm_assert_failed) { - return FALSE; - } + CRM_CHECK(id != NULL, return FALSE); if(tmp_time > graph->transition_timeout) { crm_debug("Action %d: Increasing IDLE timer to %d", action->id, tmp_time); graph->transition_timeout = tmp_time; } action->executed = TRUE; if(action->type == action_type_pseudo){ te_log_action(LOG_INFO, "Executing pseudo-event: %d", action->id); return graph_fns->pseudo(graph, action); } else if(action->type == action_type_rsc) { te_log_action(LOG_INFO, "Executing rsc-event: %d", action->id); return graph_fns->rsc(graph, action); } else if(action->type == action_type_crm) { const char *task = NULL; task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); - CRM_DEV_ASSERT(task != NULL); + CRM_CHECK(task != NULL, return FALSE); if(safe_str_eq(task, CRM_OP_FENCE)) { te_log_action(LOG_INFO, "Executing STONITH-event: %d", action->id); return graph_fns->stonith(graph, action); } te_log_action(LOG_INFO, "Executing crm-event: %d", action->id); return graph_fns->crmd(graph, action); } te_log_action(LOG_ERR, "Failed on unsupported command type: %s (id=%s)", crm_element_name(action->xml), id); return FALSE; } static gboolean fire_synapse(crm_graph_t *graph, synapse_t *synapse) { - CRM_DEV_ASSERT(synapse != NULL); - CRM_DEV_ASSERT(synapse->ready); - CRM_DEV_ASSERT(synapse->confirmed == FALSE); + CRM_CHECK(synapse != NULL, return FALSE); + CRM_CHECK(synapse->ready, return FALSE); + CRM_CHECK(synapse->confirmed == FALSE, return TRUE); crm_debug("Synapse %d fired", synapse->id); synapse->executed = TRUE; slist_iter( action, crm_action_t, synapse->actions, lpc, /* allow some leeway */ gboolean passed = FALSE; /* Invoke the action and start the timer */ passed = initiate_action(graph, action); - CRM_DEV_ASSERT(passed == TRUE); if(passed == FALSE) { crm_err("Failed initiating <%s id=%d> in synapse %d", crm_element_name(action->xml), action->id, synapse->id); return FALSE; } ); return TRUE; } int run_graph(crm_graph_t *graph) { int num_fired = 0; int num_pending = 0; int num_skipped = 0; int num_complete = 0; int num_incomplete = 0; int stat_log_level = LOG_DEBUG; int pass_result = transition_active; if(graph_fns == NULL) { set_default_graph_functions(); } if(graph == NULL) { return transition_complete; } crm_debug_2("Entering graph %d callback", graph->id); slist_iter( synapse, synapse_t, graph->synapses, lpc, if (synapse->confirmed) { crm_debug_3("Synapse %d complete", synapse->id); num_complete++; } else if (synapse->executed) { int pending_log = LOG_DEBUG; if(synapse->priority > graph->abort_priority) { pending_log = LOG_DEBUG_2; } crm_log_maybe(pending_log, "Synapse %d: confirmation pending", synapse->id); num_pending++; } else if(synapse->priority <= graph->abort_priority) { crm_debug_2("Skipping synapse %d: aborting", synapse->id); num_skipped++; } else { crm_debug_2("Synapse %d pending", synapse->id); if(should_fire_synapse(synapse)) { if(fire_synapse(graph, synapse) == FALSE) { return transition_failed; } num_fired++; } else { num_incomplete++; } } ); if(num_pending == 0 && num_fired == 0) { graph->complete = TRUE; stat_log_level = LOG_INFO; pass_result = transition_complete; if(num_incomplete != 0) { stat_log_level = LOG_WARNING; pass_result = transition_terminated; } else if(num_skipped != 0) { stat_log_level = LOG_NOTICE; } } else if(num_fired == 0) { pass_result = transition_pending; } crm_log_maybe(stat_log_level+1, "===================================================="); crm_log_maybe(stat_log_level, "Transition %d: (Complete=%d, Pending=%d," " Fired=%d, Skipped=%d, Incomplete=%d)", graph->id, num_complete, num_pending, num_fired, num_skipped, num_incomplete); return pass_result; } diff --git a/lib/crm/transition/unpack.c b/lib/crm/transition/unpack.c index 8fee0921ae..a1bcd6667c 100644 --- a/lib/crm/transition/unpack.c +++ b/lib/crm/transition/unpack.c @@ -1,258 +1,258 @@ -/* $Id: unpack.c,v 1.4 2006/02/20 16:25:50 andrew Exp $ */ +/* $Id: unpack.c,v 1.5 2006/03/18 17:23:49 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 static crm_action_t* unpack_action(synapse_t *parent, crm_data_t *xml_action) { crm_action_t *action = NULL; crm_data_t *action_copy = NULL; const char *value = crm_element_value(xml_action, XML_ATTR_ID); if(value == NULL) { crm_err("Actions must have an id!"); crm_log_xml_debug_3(xml_action, "Action with missing id"); return NULL; } action_copy = copy_xml(xml_action); crm_malloc0(action, sizeof(crm_action_t)); if(action == NULL) { return NULL; } action->id = crm_parse_int(value, NULL); action->type = action_type_rsc; action->xml = action_copy; action->synapse = parent; if(safe_str_eq(crm_element_name(action_copy), XML_GRAPH_TAG_RSC_OP)) { action->type = action_type_rsc; } else if(safe_str_eq(crm_element_name(action_copy), XML_GRAPH_TAG_PSEUDO_EVENT)) { action->type = action_type_pseudo; } else if(safe_str_eq(crm_element_name(action_copy), XML_GRAPH_TAG_CRM_EVENT)) { action->type = action_type_crm; } action->params = xml2list(action_copy); value = g_hash_table_lookup(action->params, "timeout"); if(value != NULL) { action->timeout = crm_parse_int(value, NULL); } value = g_hash_table_lookup(action->params, "interval"); if(value != NULL) { action->interval = crm_parse_int(value, NULL); } value = g_hash_table_lookup(action->params, "can_fail"); if(value != NULL) { cl_str_to_boolean(value, &(action->can_fail)); } crm_debug_3("Action %d has timer set to %dms", action->id, action->timeout); return action; } static synapse_t * unpack_synapse(crm_graph_t *new_graph, crm_data_t *xml_synapse) { const char *value = NULL; synapse_t *new_synapse = NULL; - CRM_DEV_ASSERT(xml_synapse != NULL); + CRM_CHECK(xml_synapse != NULL, return NULL); crm_debug_3("looking in synapse %s", ID(xml_synapse)); crm_malloc0(new_synapse, sizeof(synapse_t)); new_synapse->id = crm_parse_int(ID(xml_synapse), NULL); value = crm_element_value(xml_synapse, XML_CIB_ATTR_PRIORITY); if(value != NULL) { new_synapse->priority = crm_parse_int(value, NULL); } new_graph->num_synapses++; - CRM_DEV_ASSERT(new_synapse->id >= 0); + CRM_CHECK(new_synapse->id >= 0, return NULL); crm_debug_3("look for actions in synapse %s", crm_element_value(xml_synapse, XML_ATTR_ID)); xml_child_iter_filter( xml_synapse, action_set, "action_set", xml_child_iter( action_set, action, crm_action_t *new_action = unpack_action( new_synapse, action); new_graph->num_actions++; if(new_action == NULL) { continue; } crm_debug_3("Adding action %d to synapse %d", new_action->id, new_synapse->id); new_synapse->actions = g_list_append( new_synapse->actions, new_action); ); ); crm_debug_3("look for inputs in synapse %s", ID(xml_synapse)); xml_child_iter_filter( xml_synapse, inputs, "inputs", xml_child_iter( inputs, trigger, xml_child_iter( trigger, input, crm_action_t *new_input = unpack_action( new_synapse, input); if(new_input == NULL) { continue; } crm_debug_3("Adding input %d to synapse %d", new_input->id, new_synapse->id); new_synapse->inputs = g_list_append( new_synapse->inputs, new_input); ); ); ); return new_synapse; } crm_graph_t * unpack_graph(crm_data_t *xml_graph) { /* id = -1; new_graph->abort_priority = -1; new_graph->transition_timeout = -1; if(xml_graph != NULL) { t_id = crm_element_value(xml_graph, "transition_id"); time = crm_element_value(xml_graph, "global_timeout"); - CRM_DEV_ASSERT(t_id != NULL); - CRM_DEV_ASSERT(time != NULL); + CRM_CHECK(t_id != NULL, return NULL); + CRM_CHECK(time != NULL, return NULL); new_graph->transition_timeout = crm_get_msec(time); new_graph->id = crm_parse_int(t_id, "-1"); } xml_child_iter_filter( xml_graph, synapse, "synapse", synapse_t *new_synapse = unpack_synapse(new_graph, synapse); if(new_synapse != NULL) { new_graph->synapses = g_list_append( new_graph->synapses, new_synapse); } ); crm_info("Unpacked transition %d: %d actions in %d synapses", new_graph->id, new_graph->num_actions,new_graph->num_synapses); return new_graph; } static void destroy_action(crm_action_t *action) { if(action->timer) { - CRM_DEV_ASSERT(action->timer->source_id == 0); + CRM_CHECK(action->timer->source_id == 0, ;); /* Gmain_timeout_remove(action->timer->source_id); */ } g_hash_table_destroy(action->params); free_xml(action->xml); crm_free(action->timer); crm_free(action); } static void destroy_synapse(synapse_t *synapse) { while(g_list_length(synapse->actions) > 0) { crm_action_t *action = g_list_nth_data(synapse->actions, 0); synapse->actions = g_list_remove(synapse->actions, action); destroy_action(action); } while(g_list_length(synapse->inputs) > 0) { crm_action_t *action = g_list_nth_data(synapse->inputs, 0); synapse->inputs = g_list_remove(synapse->inputs, action); destroy_action(action); } crm_free(synapse); } void destroy_graph(crm_graph_t *graph) { if(graph == NULL) { return; } while(g_list_length(graph->synapses) > 0) { synapse_t *synapse = g_list_nth_data(graph->synapses, 0); graph->synapses = g_list_remove(graph->synapses, synapse); destroy_synapse(synapse); } crm_free(graph); } diff --git a/lib/crm/transition/utils.c b/lib/crm/transition/utils.c index 6974f61475..61bba38990 100644 --- a/lib/crm/transition/utils.c +++ b/lib/crm/transition/utils.c @@ -1,239 +1,239 @@ -/* $Id: utils.c,v 1.5 2006/02/20 16:25:50 andrew Exp $ */ +/* $Id: utils.c,v 1.6 2006/03/18 17:23:49 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 */ extern crm_graph_functions_t *graph_fns; static gboolean pseudo_action_dummy(crm_graph_t *graph, crm_action_t *action) { crm_debug("Dummy event handler: action %d executed", action->id); action->confirmed = TRUE; update_graph(graph, action); return TRUE; } crm_graph_functions_t default_fns = { pseudo_action_dummy, pseudo_action_dummy, pseudo_action_dummy, pseudo_action_dummy }; void set_default_graph_functions(void) { crm_info("Setting default graph functions"); graph_fns = &default_fns; } void set_graph_functions(crm_graph_functions_t *fns) { crm_info("Setting custom graph functions"); graph_fns = fns; - CRM_DEV_ASSERT(graph_fns != NULL); - CRM_DEV_ASSERT(graph_fns->rsc != NULL); - CRM_DEV_ASSERT(graph_fns->crmd != NULL); - CRM_DEV_ASSERT(graph_fns->pseudo != NULL); - CRM_DEV_ASSERT(graph_fns->stonith != NULL); + CRM_ASSERT(graph_fns != NULL); + CRM_ASSERT(graph_fns->rsc != NULL); + CRM_ASSERT(graph_fns->crmd != NULL); + CRM_ASSERT(graph_fns->pseudo != NULL); + CRM_ASSERT(graph_fns->stonith != NULL); } const char * transition_status(enum transition_status state) { switch(state) { case transition_active: return "active"; case transition_pending: return "pending"; case transition_complete: return "complete"; case transition_stopped: return "stopped"; case transition_terminated: return "terminated"; case transition_action_failed: return "failed (action)"; case transition_failed: return "failed"; } return "unknown"; } const char * actiontype2text(action_type_e type) { switch(type) { case action_type_pseudo: return "pseduo"; case action_type_rsc: return "rsc"; case action_type_crm: return "crm"; } return ""; } static void print_input(const char *prefix, crm_action_t *input, int log_level) { const char *task_uuid = crm_element_value( input->xml, XML_LRM_ATTR_TASK_KEY); crm_log_maybe(log_level, "%s[Input %d] %s (id: %s, type: %s, priority=%d)", prefix, input->id, input->confirmed?"Satisfied":"Pending", task_uuid, actiontype2text(input->type), input->synapse->priority); if(input->confirmed == FALSE) { crm_log_xml(log_level+2, "\t\t\tRaw input: ", input->xml); } } void print_graph_action(int log_level, const char *prefix, crm_action_t *action) { crm_log_maybe(log_level, "%s[Action %d] %s%s", prefix, action->id, action->confirmed?"Completed": action->executed?"In-flight": action->sent_update?"Update sent":"Pending", action->can_fail?" (can fail)":""); switch(action->type) { case action_type_pseudo: crm_log_maybe(log_level, "%s\tPseudo Op: %s", prefix, crm_element_value( action->xml, XML_LRM_ATTR_TASK)); break; case action_type_rsc: crm_log_maybe(log_level, "%s\tResource Op: %s/%s on %s", prefix, crm_element_value( action->xml, XML_LRM_ATTR_RSCID), crm_element_value( action->xml, XML_LRM_ATTR_TASK), crm_element_value( action->xml, XML_LRM_ATTR_TARGET) /* crm_element_value( */ /* action->xml, XML_LRM_ATTR_TARGET_UUID) */ ); break; case action_type_crm: crm_log_maybe(log_level, "%s\tCRM Op: %s on %s (%s)", prefix, crm_element_value( action->xml, XML_LRM_ATTR_TASK), crm_element_value( action->xml, XML_LRM_ATTR_TARGET), crm_element_value( action->xml, XML_LRM_ATTR_TARGET_UUID)); break; } if(action->timeout > 0) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s\ttimeout=%d, timer=%d", prefix, action->timeout, action->timer?action->timer->source_id:0); } if(action->confirmed == FALSE) { crm_log_xml(log_level+2, "\t\t\tRaw action: ", action->xml); } } void print_graph(unsigned int log_level, crm_graph_t *graph) { if(graph == NULL || graph->num_actions == 0) { if(log_level > LOG_DEBUG) { crm_debug("## Empty transition graph ##"); } return; } slist_iter( synapse, synapse_t, graph->synapses, lpc, crm_log_maybe(log_level, "Synapse %d %s (priority: %d)", synapse->id, synapse->confirmed?"was confirmed": synapse->executed?"was executed": "is pending", synapse->priority); if(synapse->confirmed == FALSE) { slist_iter( action, crm_action_t, synapse->actions, lpc2, print_graph_action(log_level, "\t", action); ); } if(synapse->executed == FALSE) { slist_iter( input, crm_action_t, synapse->inputs, lpc2, print_input("\t", input, log_level); ); } ); } void update_abort_priority( crm_graph_t *graph, int priority, enum transition_action action, const char *abort_reason) { if(graph == NULL) { return; } if(graph->abort_priority < priority) { graph->abort_priority = priority; crm_info("Abort priority upgraded to %d", priority); if(graph->abort_reason != NULL) { crm_info("'%s'-class abort superceeded", graph->abort_reason); } graph->abort_reason = abort_reason; } if(graph->completion_action < action) { crm_info("Abort action %d superceeded by %d", graph->completion_action, action); graph->completion_action = action; } }