Esempio n. 1
0
void
cibmon_diff(const char *event, xmlNode * msg)
{
    int rc = -1;
    const char *op = NULL;
    unsigned int log_level = LOG_INFO;

    xmlNode *diff = NULL;
    xmlNode *cib_last = NULL;
    xmlNode *update = get_message_xml(msg, F_CIB_UPDATE);

    if (msg == NULL) {
        crm_err("NULL update");
        return;
    }

    crm_element_value_int(msg, F_CIB_RC, &rc);
    op = crm_element_value(msg, F_CIB_OPERATION);
    diff = get_message_xml(msg, F_CIB_UPDATE_RESULT);

    if (rc < pcmk_ok) {
        log_level = LOG_WARNING;
        do_crm_log(log_level, "[%s] %s ABORTED: %s", event, op, pcmk_strerror(rc));
        return;
    }

    if (log_diffs) {
        log_cib_diff(log_level, diff, op);
    }

    if (log_updates && update != NULL) {
        crm_log_xml_trace(update, "raw_update");
    }

    if (cib_copy != NULL) {
        cib_last = cib_copy;
        cib_copy = NULL;
        rc = cib_process_diff(op, cib_force_diff, NULL, NULL, diff, cib_last, &cib_copy, NULL);

        if (rc != pcmk_ok) {
            crm_debug("Update didn't apply, requesting full copy: %s", pcmk_strerror(rc));
            free_xml(cib_copy);
            cib_copy = NULL;
        }
    }

    if (cib_copy == NULL) {
        cib_copy = get_cib_copy(cib);
    }

    free_xml(cib_last);
}
Esempio n. 2
0
void
te_update_diff(const char *event, xmlNode * msg)
{
    int rc = -1;
    const char *op = NULL;

    xmlNode *diff = NULL;
    xmlXPathObject *xpathObj = 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;

    CRM_CHECK(msg != NULL, return);
    crm_element_value_int(msg, F_CIB_RC, &rc);

    if (transition_graph == NULL) {
        crm_trace("No graph");
        return;

    } else if (rc < pcmk_ok) {
        crm_trace("Filter rc=%d (%s)", rc, pcmk_strerror(rc));
        return;

    } else if (transition_graph->complete == TRUE
               && fsa_state != S_IDLE
               && fsa_state != S_TRANSITION_ENGINE && fsa_state != S_POLICY_ENGINE) {
        crm_trace("Filter state=%s, complete=%d", fsa_state2string(fsa_state),
                  transition_graph->complete);
        return;
    }

    op = crm_element_value(msg, F_CIB_OPERATION);
    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_debug("Processing diff (%s): %d.%d.%d -> %d.%d.%d (%s)", op,
              diff_del_admin_epoch, diff_del_epoch, diff_del_updates,
              diff_add_admin_epoch, diff_add_epoch, diff_add_updates, fsa_state2string(fsa_state));
    log_cib_diff(LOG_DEBUG_2, diff, op);

    if (cib_config_changed(NULL, NULL, &diff)) {
        abort_transition(INFINITY, tg_restart, "Non-status change", diff);
        goto bail;              /* configuration changed */
    }

    /* Tickets Attributes - Added/Updated */
    xpathObj =
        xpath_search(diff,
                     "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//" XML_CIB_TAG_TICKETS);
    if (xpathObj && xpathObj->nodesetval->nodeNr > 0) {
        xmlNode *aborted = getXpathResult(xpathObj, 0);

        abort_transition(INFINITY, tg_restart, "Ticket attribute: update", aborted);
        goto bail;

    } else if (xpathObj) {
        xmlXPathFreeObject(xpathObj);
    }

    /* Tickets Attributes - Removed */
    xpathObj =
        xpath_search(diff,
                     "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_REMOVED "//" XML_CIB_TAG_TICKETS);
    if (xpathObj && xpathObj->nodesetval->nodeNr > 0) {
        xmlNode *aborted = getXpathResult(xpathObj, 0);

        abort_transition(INFINITY, tg_restart, "Ticket attribute: removal", aborted);
        goto bail;

    } else if (xpathObj) {
        xmlXPathFreeObject(xpathObj);
    }

    /* Transient Attributes - Added/Updated */
    xpathObj =
        xpath_search(diff,
                     "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//"
                     XML_TAG_TRANSIENT_NODEATTRS "//" XML_CIB_TAG_NVPAIR);
    if (xpathObj && xpathObj->nodesetval->nodeNr > 0) {
        int lpc;

        for (lpc = 0; lpc < xpathObj->nodesetval->nodeNr; lpc++) {
            xmlNode *attr = getXpathResult(xpathObj, lpc);
            const char *name = crm_element_value(attr, XML_NVPAIR_ATTR_NAME);
            const char *value = NULL;

            if (safe_str_eq(CRM_OP_PROBED, name)) {
                value = crm_element_value(attr, XML_NVPAIR_ATTR_VALUE);
            }

            if (crm_is_true(value) == FALSE) {
                abort_transition(INFINITY, tg_restart, "Transient attribute: update", attr);
                crm_log_xml_trace(attr, "Abort");
                goto bail;
            }
        }

    } else if (xpathObj) {
        xmlXPathFreeObject(xpathObj);
    }

    /* Transient Attributes - Removed */
    xpathObj =
        xpath_search(diff,
                     "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_REMOVED "//"
                     XML_TAG_TRANSIENT_NODEATTRS);
    if (xpathObj && xpathObj->nodesetval->nodeNr > 0) {
        xmlNode *aborted = getXpathResult(xpathObj, 0);

        abort_transition(INFINITY, tg_restart, "Transient attribute: removal", aborted);
        goto bail;

    } else if (xpathObj) {
        xmlXPathFreeObject(xpathObj);
    }

    /*
     * Check for and fast-track the processing of LRM refreshes
     * In large clusters this can result in _huge_ speedups
     *
     * Unfortunately we can only do so when there are no pending actions
     * Otherwise we could miss updates we're waiting for and stall 
     *
     */
    xpathObj = NULL;
    if (transition_graph->pending == 0) {
        xpathObj =
            xpath_search(diff,
                         "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//"
                         XML_LRM_TAG_RESOURCE);
    }

    if (xpathObj) {
        int updates = xpathObj->nodesetval->nodeNr;

        if (updates > 1) {
            /* Updates by, or in response to, TE actions will never contain updates
             * for more than one resource at a time
             */
            crm_debug("Detected LRM refresh - %d resources updated: Skipping all resource events",
                      updates);
            crm_log_xml_trace(diff, "lrm-refresh");
            abort_transition(INFINITY, tg_restart, "LRM Refresh", NULL);
            goto bail;
        }
        xmlXPathFreeObject(xpathObj);
    }

    /* Process operation updates */
    xpathObj =
        xpath_search(diff,
                     "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//" XML_LRM_TAG_RSC_OP);
    if (xpathObj) {
        process_resource_updates(xpathObj);
        xmlXPathFreeObject(xpathObj);
    }

    /* Detect deleted (as opposed to replaced or added) actions - eg. crm_resource -C */
    xpathObj = xpath_search(diff, "//" XML_TAG_DIFF_REMOVED "//" XML_LRM_TAG_RSC_OP);
    if (xpathObj) {
        int lpc = 0, max = xpathObj->nodesetval->nodeNr;

        for (lpc = 0; lpc < max; lpc++) {
            int max = 0;
            const char *op_id = NULL;
            char *rsc_op_xpath = NULL;
            xmlXPathObject *op_match = NULL;
            xmlNode *match = getXpathResult(xpathObj, lpc);

            CRM_CHECK(match != NULL, continue);

            op_id = ID(match);

            max = strlen(rsc_op_template) + strlen(op_id) + 1;
            rsc_op_xpath = calloc(1, max);
            snprintf(rsc_op_xpath, max, rsc_op_template, op_id);

            op_match = xpath_search(diff, rsc_op_xpath);
            if (op_match == NULL || op_match->nodesetval->nodeNr == 0) {
                /* Prevent false positives by matching cancelations too */
                const char *node = get_node_id(match);
                crm_action_t *cancelled = get_cancel_action(op_id, node);

                if (cancelled == NULL) {
                    crm_debug("No match for deleted action %s (%s on %s)", rsc_op_xpath, op_id,
                              node);
                    abort_transition(INFINITY, tg_restart, "Resource op removal", match);
                    if (op_match) {
                        xmlXPathFreeObject(op_match);
                    }
                    free(rsc_op_xpath);
                    goto bail;

                } else {
                    crm_debug("Deleted lrm_rsc_op %s on %s was for graph event %d",
                              op_id, node, cancelled->id);
                }
            }

            if (op_match) {
                xmlXPathFreeObject(op_match);
            }
            free(rsc_op_xpath);
        }
    }

  bail:
    if (xpathObj) {
        xmlXPathFreeObject(xpathObj);
    }
}
Esempio n. 3
0
enum cib_errors
cib_process_diff(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
                 xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
{
    unsigned int log_level = LOG_DEBUG;
    const char *reason = NULL;
    gboolean apply_diff = TRUE;
    enum cib_errors result = cib_ok;

    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_debug_2("Processing \"%s\" event", op);

    cib_diff_version_details(input,
                             &diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates,
                             &diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);

    crm_element_value_int(existing_cib, XML_ATTR_GENERATION, &this_epoch);
    crm_element_value_int(existing_cib, XML_ATTR_NUMUPDATES, &this_updates);
    crm_element_value_int(existing_cib, XML_ATTR_GENERATION_ADMIN, &this_admin_epoch);

    if (this_epoch < 0) {
        this_epoch = 0;
    }
    if (this_updates < 0) {
        this_updates = 0;
    }
    if (this_admin_epoch < 0) {
        this_admin_epoch = 0;
    }

    if (diff_del_admin_epoch == diff_add_admin_epoch
        && diff_del_epoch == diff_add_epoch && diff_del_updates == diff_add_updates) {
        if (options & cib_force_diff) {
            apply_diff = FALSE;
            log_level = LOG_ERR;
            reason = "+ and - versions in the diff did not change in global update";
            crm_log_xml_warn(input, "Bad global update");

        } else if (diff_add_admin_epoch == -1 && diff_add_epoch == -1 && diff_add_updates == -1) {
            diff_add_epoch = this_epoch;
            diff_add_updates = this_updates + 1;
            diff_add_admin_epoch = this_admin_epoch;
            diff_del_epoch = this_epoch;
            diff_del_updates = this_updates;
            diff_del_admin_epoch = this_admin_epoch;

        } else {
            apply_diff = FALSE;
            log_level = LOG_ERR;
            reason = "+ and - versions in the diff did not change";
            log_cib_diff(LOG_ERR, input, __FUNCTION__);
        }
    }

    if (apply_diff && diff_del_admin_epoch > this_admin_epoch) {
        result = cib_diff_resync;
        apply_diff = FALSE;
        log_level = LOG_INFO;
        reason = "current \"" XML_ATTR_GENERATION_ADMIN "\" is less than required";

    } else if (apply_diff && diff_del_admin_epoch < this_admin_epoch) {
        apply_diff = FALSE;
        log_level = LOG_WARNING;
        reason = "current \"" XML_ATTR_GENERATION_ADMIN "\" is greater than required";

    } else if (apply_diff && diff_del_epoch > this_epoch) {
        result = cib_diff_resync;
        apply_diff = FALSE;
        log_level = LOG_INFO;
        reason = "current \"" XML_ATTR_GENERATION "\" is less than required";

    } else if (apply_diff && diff_del_epoch < this_epoch) {
        apply_diff = FALSE;
        log_level = LOG_WARNING;
        reason = "current \"" XML_ATTR_GENERATION "\" is greater than required";

    } else if (apply_diff && diff_del_updates > this_updates) {
        result = cib_diff_resync;
        apply_diff = FALSE;
        log_level = LOG_INFO;
        reason = "current \"" XML_ATTR_NUMUPDATES "\" is less than required";

    } else if (apply_diff && diff_del_updates < this_updates) {
        apply_diff = FALSE;
        log_level = LOG_WARNING;
        reason = "current \"" XML_ATTR_NUMUPDATES "\" is greater than required";
    }

    if (apply_diff) {
        free_xml(*result_cib);
        *result_cib = NULL;
        if (apply_xml_diff(existing_cib, input, result_cib) == FALSE) {
            log_level = LOG_NOTICE;
            reason = "Failed application of an update diff";

            if (options & cib_force_diff) {
                result = cib_diff_resync;
            }
        }
    }

    if (reason != NULL) {
        do_crm_log(log_level,
                   "Diff %d.%d.%d -> %d.%d.%d not applied to %d.%d.%d: %s",
                   diff_del_admin_epoch, diff_del_epoch, diff_del_updates,
                   diff_add_admin_epoch, diff_add_epoch, diff_add_updates,
                   this_admin_epoch, this_epoch, this_updates, reason);

        crm_log_xml_trace(input, "Discarded diff");
        if (result == cib_ok) {
            result = cib_diff_failed;
        }

    } else if (apply_diff) {
        crm_debug_2("Diff %d.%d.%d -> %d.%d.%d was applied to %d.%d.%d",
                    diff_del_admin_epoch, diff_del_epoch, diff_del_updates,
                    diff_add_admin_epoch, diff_add_epoch, diff_add_updates,
                    this_admin_epoch, this_epoch, this_updates);

    }
    return result;
}
Esempio n. 4
0
void
te_update_diff(const char *event, xmlNode *msg)
{
	int rc = -1;
	const char *op = NULL;

	xmlNode *diff = NULL;
	xmlNode *cib_top = NULL;
	xmlXPathObject *xpathObj = 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;
	
	CRM_CHECK(msg != NULL, return);
	crm_element_value_int(msg, F_CIB_RC, &rc);	

	if(transition_graph == NULL) {
	    crm_debug_3("No graph");
	    return;

	} else if(rc < cib_ok) {
	    crm_debug_3("Filter rc=%d (%s)", rc, cib_error2string(rc));
	    return;

	} else if(transition_graph->complete == TRUE
		  && fsa_state != S_IDLE
		  && fsa_state != S_TRANSITION_ENGINE
		  && fsa_state != S_POLICY_ENGINE) {
	    crm_debug_2("Filter state=%s, complete=%d", fsa_state2string(fsa_state), transition_graph->complete);
	    return;
	} 	

	op = crm_element_value(msg, F_CIB_OPERATION);
	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_debug("Processing diff (%s): %d.%d.%d -> %d.%d.%d (%s)", op,
		  diff_del_admin_epoch,diff_del_epoch,diff_del_updates,
		  diff_add_admin_epoch,diff_add_epoch,diff_add_updates,
		  fsa_state2string(fsa_state));
	log_cib_diff(LOG_DEBUG_2, diff, op);

	/* Process anything that was added */
	cib_top = get_xpath_object("//"F_CIB_UPDATE_RESULT"//"XML_TAG_DIFF_ADDED"//"XML_TAG_CIB, diff, LOG_ERR);
	if(need_abort(cib_top)) {
	    goto bail; /* configuration changed */
	}

	/* Process anything that was removed */
	cib_top = get_xpath_object("//"F_CIB_UPDATE_RESULT"//"XML_TAG_DIFF_REMOVED"//"XML_TAG_CIB, diff, LOG_ERR);
	if(need_abort(cib_top)) {
	    goto bail; /* configuration changed */
	}

	/* Transient Attributes - Added/Updated */
	xpathObj = xpath_search(diff,"//"F_CIB_UPDATE_RESULT"//"XML_TAG_DIFF_ADDED"//"XML_TAG_TRANSIENT_NODEATTRS"//"XML_CIB_TAG_NVPAIR);
	if(xpathObj && xpathObj->nodesetval->nodeNr > 0) {
	    int lpc;
	    for(lpc = 0; lpc < xpathObj->nodesetval->nodeNr; lpc++) {
		xmlNode *attr = getXpathResult(xpathObj, lpc);
		const char *name = crm_element_value(attr, XML_NVPAIR_ATTR_NAME);
		const char *value = NULL;
		
		if(safe_str_eq(CRM_OP_PROBED, name)) {
		    value = crm_element_value(attr, XML_NVPAIR_ATTR_VALUE);
		}

		if(crm_is_true(value) == FALSE) {
		    abort_transition(INFINITY, tg_restart, "Transient attribute: update", attr);
		    crm_log_xml_debug_2(attr, "Abort");
		    goto bail;
		}
	    }

	} else if(xpathObj) {
	    xmlXPathFreeObject(xpathObj);
	}
	
	/* Transient Attributes - Removed */
	xpathObj = xpath_search(diff,"//"F_CIB_UPDATE_RESULT"//"XML_TAG_DIFF_REMOVED"//"XML_TAG_TRANSIENT_NODEATTRS);
	if(xpathObj && xpathObj->nodesetval->nodeNr > 0) {
	    xmlNode *aborted = getXpathResult(xpathObj, 0);
	    abort_transition(INFINITY, tg_restart, "Transient attribute: removal", aborted);
	    goto bail;

	} else if(xpathObj) {
	    xmlXPathFreeObject(xpathObj);
	}

	/* Check for node state updates... possibly from a shutdown we requested */
	xpathObj = xpath_search(diff, "//"F_CIB_UPDATE_RESULT"//"XML_TAG_DIFF_ADDED"//"XML_CIB_TAG_STATE);
	if(xpathObj) {
	    int lpc = 0, max = xpathObj->nodesetval->nodeNr;
	    for(lpc = 0; lpc < max; lpc++) {
		xmlNode *node = getXpathResult(xpathObj, lpc);
		const char *event_node = crm_element_value(node, XML_ATTR_ID);
		const char *ccm_state  = crm_element_value(node, XML_CIB_ATTR_INCCM);
		const char *ha_state   = crm_element_value(node, XML_CIB_ATTR_HASTATE);
		const char *shutdown_s = crm_element_value(node, XML_CIB_ATTR_SHUTDOWN);
		const char *crmd_state = crm_element_value(node, XML_CIB_ATTR_CRMDSTATE);

		if(safe_str_eq(ccm_state, XML_BOOLEAN_FALSE)
		   || safe_str_eq(ha_state, DEADSTATUS)
		   || safe_str_eq(crmd_state, CRMD_JOINSTATE_DOWN)) {
		    crm_action_t *shutdown = match_down_event(0, event_node, NULL);
		    
		    if(shutdown != NULL) {
			const char *task = crm_element_value(shutdown->xml, XML_LRM_ATTR_TASK);
			if(safe_str_neq(task, CRM_OP_FENCE)) {
			    /* Wait for stonithd to tell us it is complete via tengine_stonith_callback() */
			    update_graph(transition_graph, shutdown);
			    trigger_graph();
			}
			
		    } else {
			crm_info("Stonith/shutdown of %s not matched", event_node);
			abort_transition(INFINITY, tg_restart, "Node failure", node);
		    }			
		    fail_incompletable_actions(transition_graph, event_node);
		}
	 
		if(shutdown_s) {
		    int shutdown = crm_parse_int(shutdown_s, NULL);
		    if(shutdown > 0) {
			crm_info("Aborting on "XML_CIB_ATTR_SHUTDOWN" attribute for %s", event_node);
			abort_transition(INFINITY, tg_restart, "Shutdown request", node);
		    }
		}
	    }
	    xmlXPathFreeObject(xpathObj);
	}

	/*
	 * Check for and fast-track the processing of LRM refreshes
	 * In large clusters this can result in _huge_ speedups
	 *
	 * Unfortunately we can only do so when there are no pending actions
	 * Otherwise we could miss updates we're waiting for and stall 
	 *
	 */
	xpathObj = NULL;
	if(transition_graph->pending == 0) {
	    xpathObj = xpath_search(diff, "//"F_CIB_UPDATE_RESULT"//"XML_TAG_DIFF_ADDED"//"XML_LRM_TAG_RESOURCE);
	}
	
	if(xpathObj) {
	    int updates = xpathObj->nodesetval->nodeNr;
	    if(updates > 1) {
		/* Updates by, or in response to, TE actions will never contain updates
		 * for more than one resource at a time
		 */
		crm_info("Detected LRM refresh - %d resources updated: Skipping all resource events", updates);
		abort_transition(INFINITY, tg_restart, "LRM Refresh", diff);
		goto bail;
	    }
	    xmlXPathFreeObject(xpathObj);
	}

	/* Process operation updates */
	xpathObj = xpath_search(diff, "//"F_CIB_UPDATE_RESULT"//"XML_TAG_DIFF_ADDED"//"XML_LRM_TAG_RSC_OP);
	if(xpathObj) {
	    process_resource_updates(xpathObj);
	    xmlXPathFreeObject(xpathObj);
	}
	
	/* Detect deleted (as opposed to replaced or added) actions - eg. crm_resource -C */ 
	xpathObj = xpath_search(diff, "//"XML_TAG_DIFF_REMOVED"//"XML_LRM_TAG_RSC_OP);
	if(xpathObj) {
	    int lpc = 0, max = xpathObj->nodesetval->nodeNr;
	    
	    for(lpc = 0; lpc < max; lpc++) {
		int max = 0;
		const char *op_id = NULL;
		char *rsc_op_xpath = NULL;
		xmlXPathObject *op_match = NULL;
		xmlNode *match = getXpathResult(xpathObj, lpc);
		CRM_CHECK(match != NULL, continue);

		op_id = ID(match);

		max = strlen(rsc_op_template) + strlen(op_id) + 1;
		crm_malloc0(rsc_op_xpath, max);
		snprintf(rsc_op_xpath, max, rsc_op_template, op_id);
		
		op_match = xpath_search(diff, rsc_op_xpath);
		if(op_match == NULL || op_match->nodesetval->nodeNr == 0) {
		    /* Prevent false positives by matching cancelations too */
		    const char *node = get_node_id(match);
		    crm_action_t *cancelled = get_cancel_action(op_id, node);

		    if(cancelled == NULL) {
			crm_debug("No match for deleted action %s (%s on %s)", rsc_op_xpath, op_id, node);
			abort_transition(INFINITY, tg_restart, "Resource op removal", match);
			if(op_match) {
			    xmlXPathFreeObject(op_match);
			}
			crm_free(rsc_op_xpath);
			goto bail;

		    } else {
			crm_debug("Deleted lrm_rsc_op %s on %s was for graph event %d",
				  op_id, node, cancelled->id);
		    }
		}

		if(op_match) {
		    xmlXPathFreeObject(op_match);
		}
		crm_free(rsc_op_xpath);
	    }
	}

  bail:
	if(xpathObj) {
	    xmlXPathFreeObject(xpathObj);
	}
}
Esempio n. 5
0
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_debug("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) {
		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 *attrs = NULL;
		crm_data_t *status = 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 && change_set != NULL) {
			status = get_object_root(XML_CIB_TAG_STATUS, change_set);
		
			xml_child_iter_filter(
				status, node_state, XML_CIB_TAG_STATE,
				
				attrs = find_xml_node(
					node_state, XML_TAG_TRANSIENT_NODEATTRS, FALSE);
				
				if(attrs != NULL) {
					crm_info("Aborting on "XML_TAG_TRANSIENT_NODEATTRS" deletions");
					abort_transition(INFINITY, tg_restart,
							 XML_TAG_TRANSIENT_NODEATTRS, attrs);
				}
				);
Esempio n. 6
0
enum cib_errors 
cib_process_diff(
	const char *op, int options, const char *section, crm_data_t *input,
	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
	unsigned int log_level = LOG_DEBUG;
	const char *value = NULL;
	const char *reason = NULL;
	gboolean apply_diff = TRUE;
	gboolean do_resync = FALSE;
	enum cib_errors result = cib_ok;

	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_debug_2("Processing \"%s\" event", op);

	if(cib_is_master) {
		/* the master is never waiting for a resync */
		sync_in_progress = 0;
	}
	
	cib_diff_version_details(
		input,
		&diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates, 
		&diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);

	if(sync_in_progress > MAX_DIFF_RETRY) {
		/* request another full-sync,
		 * the last request may have been lost
		 */
		sync_in_progress = 0;
	} 
	if(sync_in_progress) {
		sync_in_progress++;
		crm_warn("Not applying diff %d.%d.%d -> %d.%d.%d (sync in progress)",
			diff_del_admin_epoch,diff_del_epoch,diff_del_updates,
			diff_add_admin_epoch,diff_add_epoch,diff_add_updates);
		return cib_diff_resync;
	}
	
	value = crm_element_value(existing_cib, XML_ATTR_GENERATION);
	this_epoch = atoi(value?value:"0");
	
	value = crm_element_value(existing_cib, XML_ATTR_NUMUPDATES);
	this_updates = atoi(value?value:"0");
	
	value = crm_element_value(existing_cib, XML_ATTR_GENERATION_ADMIN);
	this_admin_epoch = atoi(value?value:"0");
	
	if(diff_del_admin_epoch == diff_add_admin_epoch
	   && diff_del_epoch == diff_add_epoch
	   && diff_del_updates == diff_add_updates) {
		if(diff_add_admin_epoch == -1 && diff_add_epoch == -1 && diff_add_updates == -1) {
			diff_add_epoch = this_epoch;
			diff_add_updates = this_updates + 1;
			diff_add_admin_epoch = this_admin_epoch;
			diff_del_epoch = this_epoch;
			diff_del_updates = this_updates;
			diff_del_admin_epoch = this_admin_epoch;
		} else {
			apply_diff = FALSE;
			log_level = LOG_ERR;
			reason = "+ and - versions in the diff did not change";
			log_cib_diff(LOG_ERR, input, __FUNCTION__);
		}
	}

	if(apply_diff && diff_del_admin_epoch > this_admin_epoch) {
		do_resync = TRUE;
		apply_diff = FALSE;
		log_level = LOG_INFO;
		reason = "current \""XML_ATTR_GENERATION_ADMIN"\" is less than required";
		
	} else if(apply_diff && diff_del_admin_epoch < this_admin_epoch) {
		apply_diff = FALSE;
		log_level = LOG_WARNING;
		reason = "current \""XML_ATTR_GENERATION_ADMIN"\" is greater than required";
	}

	if(apply_diff && diff_del_epoch > this_epoch) {
		do_resync = TRUE;
		apply_diff = FALSE;
		log_level = LOG_INFO;
		reason = "current \""XML_ATTR_GENERATION"\" is less than required";
		
	} else if(apply_diff && diff_del_epoch < this_epoch) {
		apply_diff = FALSE;
		log_level = LOG_WARNING;
		reason = "current \""XML_ATTR_GENERATION"\" is greater than required";
	}

	if(apply_diff && diff_del_updates > this_updates) {
		do_resync = TRUE;
		apply_diff = FALSE;
		log_level = LOG_INFO;
		reason = "current \""XML_ATTR_NUMUPDATES"\" is less than required";
		
	} else if(apply_diff && diff_del_updates < this_updates) {
		apply_diff = FALSE;
		log_level = LOG_WARNING;
		reason = "current \""XML_ATTR_NUMUPDATES"\" is greater than required";
	}

	if(apply_diff) {
		free_xml(*result_cib);
		*result_cib = NULL;
		if(apply_xml_diff(existing_cib, input, result_cib) == FALSE) {
			log_level = LOG_WARNING;
			reason = "Failed application of an update diff";

			if(options & cib_force_diff) {
			    if(cib_is_master == FALSE) {
				log_level = LOG_INFO;
				reason = "Failed application of a global update."
					 "  Requesting full refresh.";
				do_resync = TRUE;

			    } else {
				reason = "Failed application of a global update."
					 "  Not requesting full refresh.";
			    }
			}
			
		} else if((options & cib_force_diff) && !validate_with_dtd(
			      *result_cib, FALSE, HA_NOARCHDATAHBDIR"/crm.dtd")) {

		    if(cib_is_master == FALSE) {
			log_level = LOG_INFO;
			reason = "Failed DTD validation of a global update."
				 "  Requesting full refresh.";
			do_resync = TRUE;
		    } else {
			log_level = LOG_WARNING;
			reason = "Failed DTD validation of a global update."
				 "  Not requesting full refresh.";
		    }
		}
	}
	
	if(reason != NULL) {
		do_crm_log(
			log_level,
			"Diff %d.%d.%d -> %d.%d.%d not applied to %d.%d.%d: %s",
			diff_del_admin_epoch,diff_del_epoch,diff_del_updates,
			diff_add_admin_epoch,diff_add_epoch,diff_add_updates,
			this_admin_epoch,this_epoch,this_updates, reason);
		
		result = cib_diff_failed;

	} else if(apply_diff) {
		crm_debug_2("Diff %d.%d.%d -> %d.%d.%d was applied",
			    diff_del_admin_epoch,diff_del_epoch,diff_del_updates,
			    diff_add_admin_epoch,diff_add_epoch,diff_add_updates);
	}

	if(do_resync && cib_is_master == FALSE) {
		HA_Message *sync_me = ha_msg_new(3);
		free_xml(*result_cib);
		*result_cib = NULL;
		result = cib_diff_resync;
		crm_info("Requesting re-sync from peer: %s", reason);
		sync_in_progress++;
		
		ha_msg_add(sync_me, F_TYPE, "cib");
		ha_msg_add(sync_me, F_CIB_OPERATION, CIB_OP_SYNC_ONE);
		ha_msg_add(sync_me, F_CIB_DELEGATED, cib_our_uname);

		if(send_ha_message(hb_conn, sync_me, NULL, FALSE) == FALSE) {
			result = cib_not_connected;
		}
		ha_msg_del(sync_me);
		
	} else if(do_resync) {
		crm_err("Not resyncing in master mode");
	}
	
	
	return result;
}