Beispiel #1
0
static void
add_notify_data_to_action_meta(notify_data_t *n_data, pe_action_t *action)
{
    for (GSList *item = n_data->keys; item; item = item->next) {
        pcmk_nvpair_t *nvpair = item->data;

        add_hash_param(action->meta, nvpair->name, nvpair->value);
    }
}
Beispiel #2
0
static void CancelXmlOp(resource_t *rsc, xmlNode *xml_op, node_t *active_node,
			const char *reason, pe_working_set_t *data_set) 
{
    int interval = 0;
    action_t *cancel = NULL;

    char *key = NULL;
    const char *task = NULL;
    const char *call_id = NULL;
    const char *op_version = NULL;
    const char *interval_s = NULL;
    
    CRM_CHECK(xml_op != NULL, return);
    CRM_CHECK(active_node != NULL, return);

    task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
    call_id = crm_element_value(xml_op, XML_LRM_ATTR_CALLID);
    op_version = crm_element_value(xml_op, XML_ATTR_CRM_VERSION);
    interval_s = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL);
    
    interval = crm_parse_int(interval_s, "0");

    /* we need to reconstruct the key because of the way we used to construct resource IDs */
    key = generate_op_key(rsc->id, task, interval);
    
    crm_info("Action %s on %s will be stopped: %s",
	     key, active_node->details->uname, reason?reason:"unknown");

    cancel = custom_action(rsc, crm_strdup(key), RSC_CANCEL,
			   active_node, FALSE, TRUE, data_set);

    crm_free(cancel->task);
    cancel->task = crm_strdup(RSC_CANCEL);
    
    add_hash_param(cancel->meta, XML_LRM_ATTR_TASK,     task);
    add_hash_param(cancel->meta, XML_LRM_ATTR_CALLID,   call_id);
    add_hash_param(cancel->meta, XML_LRM_ATTR_INTERVAL, interval_s);
    
    custom_action_order(rsc, stop_key(rsc), NULL,
			rsc, NULL, cancel, pe_order_optional, data_set);
    crm_free(key); key = NULL;
}
Beispiel #3
0
void
get_meta_attributes(GHashTable *meta_hash, resource_t *rsc,
		    node_t *node, pe_working_set_t *data_set)
{
	GHashTable *node_hash = NULL;
	if(node) {
		node_hash = node->details->attrs;
	}
	
	xml_prop_iter(rsc->xml, prop_name, prop_value,
		      add_hash_param(meta_hash, prop_name, prop_value);
		);
Beispiel #4
0
resource_t *
create_child_clone(resource_t * rsc, int sub_id, pe_working_set_t * data_set)
{
    gboolean as_orphan = FALSE;
    char *inc_num = NULL;
    char *inc_max = NULL;
    resource_t *child_rsc = NULL;
    xmlNode *child_copy = NULL;
    clone_variant_data_t *clone_data = NULL;

    get_clone_variant_data(clone_data, rsc);

    CRM_CHECK(clone_data->xml_obj_child != NULL, return FALSE);

    if (sub_id < 0) {
        as_orphan = TRUE;
        sub_id = clone_data->total_clones;
    }
    inc_num = crm_itoa(sub_id);
    inc_max = crm_itoa(clone_data->clone_max);

    child_copy = copy_xml(clone_data->xml_obj_child);

    crm_xml_add(child_copy, XML_RSC_ATTR_INCARNATION, inc_num);

    if (common_unpack(child_copy, &child_rsc, rsc, data_set) == FALSE) {
        pe_err("Failed unpacking resource %s", crm_element_value(child_copy, XML_ATTR_ID));
        child_rsc = NULL;
        goto bail;
    }
/*  child_rsc->globally_unique = rsc->globally_unique; */

    CRM_ASSERT(child_rsc);
    clone_data->total_clones += 1;
    pe_rsc_trace(child_rsc, "Setting clone attributes for: %s", child_rsc->id);
    rsc->children = g_list_append(rsc->children, child_rsc);
    if (as_orphan) {
        mark_as_orphan(child_rsc);
    }

    add_hash_param(child_rsc->meta, XML_RSC_ATTR_INCARNATION_MAX, inc_max);

    print_resource(LOG_DEBUG_3, "Added ", child_rsc, FALSE);

  bail:
    free(inc_num);
    free(inc_max);

    return child_rsc;
}
Beispiel #5
0
void
get_meta_attributes(GHashTable * meta_hash, resource_t * rsc,
                    node_t * node, pe_working_set_t * data_set)
{
    GHashTable *node_hash = NULL;
    const char *version = crm_element_value(data_set->input, XML_ATTR_CRM_VERSION);

    if (node) {
        node_hash = node->details->attrs;
    }

    if (rsc->xml) {
        xmlAttrPtr xIter = NULL;

        for (xIter = rsc->xml->properties; xIter; xIter = xIter->next) {
            const char *prop_name = (const char *)xIter->name;
            const char *prop_value = crm_element_value(rsc->xml, prop_name);

            add_hash_param(meta_hash, prop_name, prop_value);
        }
    }

    unpack_instance_attributes(data_set->input, rsc->xml, XML_TAG_META_SETS, node_hash,
                               meta_hash, NULL, FALSE, data_set->now);

    if(version == NULL || compare_version(version, "3.0.9") < 0) {
        /* populate from the regular attributes until the GUI can create
         * meta attributes
         */
        unpack_instance_attributes(data_set->input, rsc->xml, XML_TAG_ATTR_SETS, node_hash,
                                   meta_hash, NULL, FALSE, data_set->now);
    }

    /* set anything else based on the parent */
    if (rsc->parent != NULL) {
        g_hash_table_foreach(rsc->parent->meta, dup_attr, meta_hash);
    }

    /* and finally check the defaults */
    unpack_instance_attributes(data_set->input, data_set->rsc_defaults, XML_TAG_META_SETS,
                               node_hash, meta_hash, NULL, FALSE, data_set->now);
}
Beispiel #6
0
static void
dup_attr(gpointer key, gpointer value, gpointer user_data)
{
    add_hash_param(user_data, key, value);
}
Beispiel #7
0
static gboolean
check_action_definition(resource_t *rsc, node_t *active_node, crm_data_t *xml_op,
			pe_working_set_t *data_set)
{
	char *key = NULL;
	int interval = 0;
	const char *interval_s = NULL;
	
	gboolean did_change = FALSE;
	gboolean start_op = FALSE;

	crm_data_t *params_all = NULL;
	crm_data_t *params_restart = NULL;
	GHashTable *local_rsc_params = NULL;
	
	char *digest_all_calc = NULL;
	const char *digest_all = NULL;

	const char *restart_list = NULL;
	const char *digest_restart = NULL;
	char *digest_restart_calc = NULL;

	action_t *action = NULL;
	const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
	const char *op_version = crm_element_value(xml_op, XML_ATTR_CRM_VERSION);

	CRM_CHECK(active_node != NULL, return FALSE);

	interval_s = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL);
	interval = crm_parse_int(interval_s, "0");
	/* we need to reconstruct the key because of the way we used to construct resource IDs */
	key = generate_op_key(rsc->id, task, interval);

	if(interval > 0) {
		crm_data_t *op_match = NULL;

		crm_debug_2("Checking parameters for %s", key);
		op_match = find_rsc_op_entry(rsc, key);

		if(op_match == NULL && data_set->stop_action_orphans) {
			/* create a cancel action */
			action_t *cancel = NULL;
			char *cancel_key = NULL;
			const char *call_id = crm_element_value(xml_op, XML_LRM_ATTR_CALLID);
			
			crm_info("Orphan action will be stopped: %s on %s",
				 key, active_node->details->uname);

			cancel_key = generate_op_key(
				rsc->id, CRMD_ACTION_CANCEL, interval);

			cancel = custom_action(
				rsc, cancel_key, CRMD_ACTION_CANCEL,
				active_node, FALSE, TRUE, data_set);

			add_hash_param(cancel->meta, XML_LRM_ATTR_TASK,     task);
			add_hash_param(cancel->meta, XML_LRM_ATTR_CALLID,   call_id);
			add_hash_param(cancel->meta, XML_LRM_ATTR_INTERVAL, interval_s);

			custom_action_order(	
				rsc, stop_key(rsc), NULL,
				rsc, NULL, cancel,
				pe_order_optional, data_set);
			crm_free(key); key = NULL;
			return TRUE;

		} else if(op_match == NULL) {
			crm_debug("Orphan action detected: %s on %s",
				  key, active_node->details->uname);
			crm_free(key); key = NULL;
			return TRUE;
		}
	}

	action = custom_action(rsc, key, task, active_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, active_node->details->attrs,
		local_rsc_params, NULL, data_set->now);
	
	params_all = create_xml_node(NULL, XML_TAG_PARAMS);
	g_hash_table_foreach(action->extra, hash2field, params_all);
	g_hash_table_foreach(rsc->parameters, hash2field, params_all);
	g_hash_table_foreach(action->meta, hash2metafield, params_all);
	g_hash_table_foreach(local_rsc_params, hash2field, params_all);

	filter_action_parameters(params_all, op_version);
	digest_all_calc = calculate_xml_digest(params_all, TRUE, FALSE);
	digest_all = crm_element_value(xml_op, XML_LRM_ATTR_OP_DIGEST);
	digest_restart = crm_element_value(xml_op, XML_LRM_ATTR_RESTART_DIGEST);
	restart_list = crm_element_value(xml_op, XML_LRM_ATTR_OP_RESTART);

	if(crm_str_eq(task, CRMD_ACTION_START, TRUE)) {
		start_op = TRUE;
	}
	
	if(start_op && digest_restart) {
		params_restart = copy_xml(params_all);
		if(restart_list) {
			filter_reload_parameters(params_restart, restart_list);
		}

		digest_restart_calc = calculate_xml_digest(params_restart, TRUE, FALSE);
		if(safe_str_neq(digest_restart_calc, digest_restart)) {
			did_change = TRUE;
			crm_log_xml_info(params_restart, "params:restart");
			crm_warn("Parameters to %s on %s changed: recorded %s vs. %s (restart:%s) %s",
				 key, active_node->details->uname,
				 crm_str(digest_restart), digest_restart_calc,
				 op_version, crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC));
			
			key = generate_op_key(rsc->id, task, interval);
			custom_action(rsc, key, task, NULL, FALSE, TRUE, data_set);
			goto cleanup;
		}
	}

	if(safe_str_neq(digest_all_calc, digest_all)) {
		action_t *op = NULL;
		did_change = TRUE;
		crm_log_xml_info(params_all, "params:all");
 		crm_warn("Parameters to %s on %s changed: recorded %s vs. %s (all:%s) %s",
			 key, active_node->details->uname,
			 crm_str(digest_all), digest_all_calc, op_version,
			 crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC));
		
		key = generate_op_key(rsc->id, task, interval);
		op = custom_action(rsc, key, task, NULL, FALSE, TRUE, data_set);
		if(start_op && digest_restart) {
			op->allow_reload_conversion = TRUE;

		} else if(interval > 0) {
			custom_action_order(rsc, start_key(rsc), NULL,
					    NULL, crm_strdup(op->task), op,
					    pe_order_runnable_left, data_set);
		}
		
	}

  cleanup:
	free_xml(params_all);
	free_xml(params_restart);
	crm_free(digest_all_calc);
	crm_free(digest_restart_calc);
	g_hash_table_destroy(local_rsc_params);

	pe_free_action(action);
	
	return did_change;
}
Beispiel #8
0
notify_data_t *
create_notification_boundaries(resource_t * rsc, const char *action, action_t * start,
                               action_t * end, pe_working_set_t * data_set)
{
    /* Create the pseudo ops that preceed and follow the actual notifications */

    /*
     * Creates two sequences (conditional on start and end being supplied):
     *   pre_notify -> pre_notify_complete -> start, and
     *   end -> post_notify -> post_notify_complete
     *
     * 'start' and 'end' may be the same event or ${X} and ${X}ed as per clones
     */
    char *key = NULL;
    notify_data_t *n_data = NULL;

    if (is_not_set(rsc->flags, pe_rsc_notify)) {
        return NULL;
    }

    n_data = calloc(1, sizeof(notify_data_t));
    n_data->action = action;
    n_data->keys =
        g_hash_table_new_full(crm_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str);

    if (start) {
        /* create pre-event notification wrappers */
        key = generate_notify_key(rsc->id, "pre", start->task);
        n_data->pre =
            custom_action(rsc, key, RSC_NOTIFY, NULL, is_set(start->flags, pe_action_optional),
                          TRUE, data_set);

        update_action_flags(n_data->pre, pe_action_pseudo, __FUNCTION__);
        update_action_flags(n_data->pre, pe_action_runnable, __FUNCTION__);

        add_hash_param(n_data->pre->meta, "notify_type", "pre");
        add_hash_param(n_data->pre->meta, "notify_operation", n_data->action);

        add_hash_param(n_data->pre->meta, "notify_key_type", "pre");
        add_hash_param(n_data->pre->meta, "notify_key_operation", start->task);

        /* create pre_notify_complete */
        key = generate_notify_key(rsc->id, "confirmed-pre", start->task);
        n_data->pre_done =
            custom_action(rsc, key, RSC_NOTIFIED, NULL, is_set(start->flags, pe_action_optional),
                          TRUE, data_set);

        update_action_flags(n_data->pre_done, pe_action_pseudo, __FUNCTION__);
        update_action_flags(n_data->pre_done, pe_action_runnable, __FUNCTION__);

        add_hash_param(n_data->pre_done->meta, "notify_type", "pre");
        add_hash_param(n_data->pre_done->meta, "notify_operation", n_data->action);

        add_hash_param(n_data->pre_done->meta, "notify_key_type", "confirmed-pre");
        add_hash_param(n_data->pre_done->meta, "notify_key_operation", start->task);

        order_actions(n_data->pre_done, start, pe_order_optional);
        order_actions(n_data->pre, n_data->pre_done, pe_order_optional);
    }

    if (end) {
        /* create post-event notification wrappers */
        key = generate_notify_key(rsc->id, "post", end->task);
        n_data->post =
            custom_action(rsc, key, RSC_NOTIFY, NULL, is_set(end->flags, pe_action_optional), TRUE,
                          data_set);

        n_data->post->priority = INFINITY;
        update_action_flags(n_data->post, pe_action_pseudo, __FUNCTION__);
        if (is_set(end->flags, pe_action_runnable)) {
            update_action_flags(n_data->post, pe_action_runnable, __FUNCTION__);
        } else {
            update_action_flags(n_data->post, pe_action_runnable | pe_action_clear, __FUNCTION__);
        }

        add_hash_param(n_data->post->meta, "notify_type", "post");
        add_hash_param(n_data->post->meta, "notify_operation", n_data->action);

        add_hash_param(n_data->post->meta, "notify_key_type", "post");
        add_hash_param(n_data->post->meta, "notify_key_operation", end->task);

        /* create post_notify_complete */
        key = generate_notify_key(rsc->id, "confirmed-post", end->task);
        n_data->post_done =
            custom_action(rsc, key, RSC_NOTIFIED, NULL, is_set(end->flags, pe_action_optional),
                          TRUE, data_set);

        n_data->post_done->priority = INFINITY;
        update_action_flags(n_data->post_done, pe_action_pseudo, __FUNCTION__);
        if (is_set(end->flags, pe_action_runnable)) {
            update_action_flags(n_data->post_done, pe_action_runnable, __FUNCTION__);
        } else {
            update_action_flags(n_data->post_done, pe_action_runnable | pe_action_clear, __FUNCTION__);
        }

        add_hash_param(n_data->post_done->meta, "notify_type", "post");
        add_hash_param(n_data->post_done->meta, "notify_operation", n_data->action);

        add_hash_param(n_data->post_done->meta, "notify_key_type", "confirmed-post");
        add_hash_param(n_data->post_done->meta, "notify_key_operation", end->task);

        order_actions(end, n_data->post, pe_order_implies_then);
        order_actions(n_data->post, n_data->post_done, pe_order_implies_then);
    }

    if (start && end) {
        order_actions(n_data->pre_done, n_data->post, pe_order_optional);
    }

    if (safe_str_eq(action, RSC_STOP)) {
        action_t *all_stopped = get_pseudo_op(ALL_STOPPED, data_set);

        order_actions(n_data->post_done, all_stopped, pe_order_optional);
    }

    return n_data;
}
Beispiel #9
0
gboolean
clone_unpack(resource_t * rsc, pe_working_set_t * data_set)
{
    int lpc = 0;
    const char *type = NULL;
    int num_xml_children = 0;
    xmlNode *a_child = NULL;
    xmlNode *xml_obj = rsc->xml;
    clone_variant_data_t *clone_data = NULL;

    const char *ordered = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_ORDERED);
    const char *interleave = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INTERLEAVE);
    const char *max_clones = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INCARNATION_MAX);
    const char *max_clones_node = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INCARNATION_NODEMAX);

    pe_rsc_trace(rsc, "Processing resource %s...", rsc->id);

    clone_data = calloc(1, sizeof(clone_variant_data_t));
    rsc->variant_opaque = clone_data;
    clone_data->interleave = FALSE;
    clone_data->ordered = FALSE;

    clone_data->active_clones = 0;
    clone_data->xml_obj_child = NULL;
    clone_data->clone_node_max = crm_parse_int(max_clones_node, "1");

    if (max_clones) {
        clone_data->clone_max = crm_parse_int(max_clones, "1");

    } else if (g_list_length(data_set->nodes) > 0) {
        clone_data->clone_max = g_list_length(data_set->nodes);

    } else {
        clone_data->clone_max = 1;      /* Handy during crm_verify */
    }

    if (crm_is_true(interleave)) {
        clone_data->interleave = TRUE;
    }
    if (crm_is_true(ordered)) {
        clone_data->ordered = TRUE;
    }
    if ((rsc->flags & pe_rsc_unique) == 0 && clone_data->clone_node_max > 1) {
        crm_config_err("Anonymous clones (%s) may only support one copy per node", rsc->id);
        clone_data->clone_node_max = 1;
    }

    pe_rsc_trace(rsc, "Options for %s", rsc->id);
    pe_rsc_trace(rsc, "\tClone max: %d", clone_data->clone_max);
    pe_rsc_trace(rsc, "\tClone node max: %d", clone_data->clone_node_max);
    pe_rsc_trace(rsc, "\tClone is unique: %s",
                 is_set(rsc->flags, pe_rsc_unique) ? "true" : "false");

    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);
        for (a_child = __xml_first_child(xml_obj); a_child != NULL; a_child = __xml_next_element(a_child)) {
            if (crm_str_eq((const char *)a_child->name, XML_CIB_TAG_RESOURCE, TRUE)) {
                num_xml_children++;
            }
        }
    }

    if (clone_data->xml_obj_child == NULL) {
        crm_config_err("%s has nothing to clone", rsc->id);
        return FALSE;
    }

    for (a_child = __xml_first_child(xml_obj); a_child != NULL; a_child = __xml_next_element(a_child)) {
        if (crm_str_eq((const char *)a_child->name, type, TRUE)) {
            num_xml_children++;
        }
    }

    if (num_xml_children > 1) {
        crm_config_err("%s has too many children.  Only the first (%s) will be cloned.",
                       rsc->id, ID(clone_data->xml_obj_child));
    }

    /*
     * Make clones ever so slightly sticky by default
     *
     * This helps ensure clone instances are not shuffled around the cluster
     * for no benefit in situations when pre-allocation is not appropriate
     */
    if (g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_STICKINESS) == NULL) {
        add_hash_param(rsc->meta, XML_RSC_ATTR_STICKINESS, "1");
    }

    pe_rsc_trace(rsc, "\tClone is unique (fixed): %s",
                 is_set(rsc->flags, pe_rsc_unique) ? "true" : "false");
    clone_data->notify_confirm = is_set(rsc->flags, pe_rsc_notify);
    add_hash_param(rsc->meta, XML_RSC_ATTR_UNIQUE,
                   is_set(rsc->flags, pe_rsc_unique) ? XML_BOOLEAN_TRUE : XML_BOOLEAN_FALSE);

    for (lpc = 0; lpc < clone_data->clone_max; lpc++) {
        if (create_child_clone(rsc, lpc, data_set) == NULL) {
            return FALSE;
        }
    }

    if (clone_data->clone_max == 0) {
        /* create one so that unpack_find_resource() will hook up
         * any orphans up to the parent correctly
         */
        if (create_child_clone(rsc, -1, data_set) == NULL) {
            return FALSE;
        }
    }

    pe_rsc_trace(rsc, "Added %d children to resource %s...", clone_data->clone_max, rsc->id);
    return TRUE;
}