21#include <libxml/tree.h>
33add_xml_changes_to_patchset(xmlNode *xml, xmlNode *patchset)
35 xmlNode *cIter = NULL;
36 xmlAttr *pIter = NULL;
37 xmlNode *change = NULL;
39 const char *value = NULL;
41 if (nodepriv == NULL) {
62 g_string_free(xpath, TRUE);
69 for (pIter = pcmk__xe_first_attr(xml); pIter != NULL;
70 pIter = pIter->next) {
73 nodepriv = pIter->_private;
88 g_string_free(xpath, TRUE);
101 value = pcmk__xml_attr_value(pIter);
112 for (pIter = pcmk__xe_first_attr(xml); pIter != NULL;
113 pIter = pIter->next) {
114 nodepriv = pIter->_private;
123 for (cIter = pcmk__xml_first_child(xml); cIter != NULL;
124 cIter = pcmk__xml_next(cIter)) {
125 add_xml_changes_to_patchset(cIter, patchset);
128 nodepriv = xml->_private;
133 xml->name, pcmk__xe_id(xml),
143 g_string_free(xpath, TRUE);
149is_config_change(xmlNode *xml)
158 nodepriv = config->_private;
164 if ((xml->doc != NULL) && (xml->doc->_private != NULL)) {
165 docpriv = xml->doc->_private;
166 for (gIter = docpriv->
deleted_objs; gIter; gIter = gIter->next) {
169 if (strstr(deleted_obj->
path,
179xml_create_patchset_v2(xmlNode *source, xmlNode *
target)
187 xmlNode *patchset = NULL;
188 const char *vfields[] = {
201 docpriv =
target->doc->_private;
228 for (gIter = docpriv->
deleted_objs; gIter; gIter = gIter->next) {
239 add_xml_changes_to_patchset(
target, patchset);
245 bool *config_changed,
bool manage_version)
247 bool local_config_changed =
false;
253 crm_err(
"Unknown patch format: %d", format);
265 if (config_changed == NULL) {
266 config_changed = &local_config_changed;
268 *config_changed = is_config_change(
target);
270 if (manage_version) {
273 if (*config_changed) {
285 return xml_create_patchset_v2(source,
target);
294 if ((patch == NULL) || (source == NULL) || (
target == NULL)
317 static const char *
const vfields[] = {
333 crm_err(
"Unknown patch format: %d", format);
337 if (source != NULL) {
340 crm_trace(
"Got %d for del[%s]", del[i], vfields[i]);
347 crm_trace(
"Got %d for add[%s]", add[i], vfields[i]);
363xml_patch_version_check(
const xmlNode *xml,
const xmlNode *patchset)
366 bool changed = FALSE;
368 int this[] = { 0, 0, 0 };
369 int add[] = { 0, 0, 0 };
370 int del[] = { 0, 0, 0 };
372 const char *vfields[] = {
380 crm_trace(
"Got %d for this[%s]",
this[lpc], vfields[lpc]);
389 add[2] =
this[2] + 1;
391 del[lpc] =
this[lpc];
397 if (
this[lpc] < del[lpc]) {
398 crm_debug(
"Current %s is too low (%d.%d.%d < %d.%d.%d --> %d.%d.%d)",
399 vfields[lpc],
this[0],
this[1],
this[2],
400 del[0], del[1], del[2], add[0], add[1], add[2]);
403 }
else if (
this[lpc] > del[lpc]) {
404 crm_info(
"Current %s is too high (%d.%d.%d > %d.%d.%d --> %d.%d.%d) %p",
405 vfields[lpc],
this[0],
this[1],
this[2],
406 del[0], del[1], del[2], add[0], add[1], add[2], patchset);
413 if (add[lpc] > del[lpc]) {
419 crm_notice(
"Versions did not change in patch %d.%d.%d",
420 add[0], add[1], add[2]);
424 crm_debug(
"Can apply patch %d.%d.%d to %d.%d.%d",
425 add[0], add[1], add[2],
this[0],
this[1],
this[2]);
431first_matching_xml_child(
const xmlNode *
parent,
const char *
name,
432 const char *
id,
int position)
434 xmlNode *cIter = NULL;
436 for (cIter = pcmk__xml_first_child(
parent); cIter != NULL;
437 cIter = pcmk__xml_next(cIter)) {
438 if (strcmp((
const char *) cIter->name,
name) != 0) {
441 const char *cid = pcmk__xe_id(cIter);
443 if ((cid == NULL) || (strcmp(cid,
id) != 0)) {
449 if ((cIter->type == XML_COMMENT_NODE)
474search_v2_xpath(
const xmlNode *top,
const char *key,
int target_position)
476 xmlNode *
target = (xmlNode *) top->doc;
477 const char *current = key;
487 key_len = strlen(key);
500 rc = sscanf(current,
"/%[^/]%s", section, remainder);
503 int f = sscanf(section,
"%[^[][@" PCMK_XA_ID "='%[^']", tag,
id);
504 int current_position = -1;
509 if ((rc == 1) && (target_position >= 0)) {
510 current_position = target_position;
531 }
while ((rc == 2) &&
target);
535 (
path = (
char *) xmlGetNodePath(
target)), key);
548typedef struct xml_change_obj_s {
549 const xmlNode *change;
554sort_change_obj_by_position(gconstpointer a, gconstpointer b)
564 if (position_a < position_b) {
567 }
else if (position_a > position_b) {
584apply_v2_patchset(xmlNode *xml,
const xmlNode *patchset)
587 const xmlNode *change = NULL;
588 GList *change_objs = NULL;
591 for (change = pcmk__xml_first_child(patchset); change != NULL;
592 change = pcmk__xml_next(change)) {
593 xmlNode *match = NULL;
602 crm_trace(
"Processing %s %s", change->name, op);
610 match = search_v2_xpath(xml, xpath, position);
611 crm_trace(
"Performing %s on %s with %p", op, xpath, match);
614 crm_debug(
"No %s match for %s in %p", op, xpath, xml->doc);
617 }
else if (match == NULL) {
618 crm_err(
"No %s match for %s in %p", op, xpath, xml->doc);
628 change_obj->change = change;
629 change_obj->match = match;
631 change_objs = g_list_append(change_objs, change_obj);
635 if ((match->parent != NULL) && (match->parent->last != NULL)) {
636 xmlAddNextSibling(match->parent->last, match);
647 const xmlNode *attrs = pcmk__xml_first_child(child);
657 for (xmlAttrPtr pIter = pcmk__xe_first_attr(attrs); pIter != NULL;
658 pIter = pIter->next) {
659 const char *
name = (
const char *) pIter->name;
660 const char *value = pcmk__xml_attr_value(pIter);
666 crm_err(
"Unknown operation: %s", op);
672 change_objs = g_list_sort(change_objs, sort_change_obj_by_position);
674 for (gIter = change_objs; gIter; gIter = gIter->next) {
676 xmlNode *match = change_obj->match;
677 const char *op = NULL;
678 const char *xpath = NULL;
680 change = change_obj->change;
685 crm_trace(
"Continue performing %s on %s with %p", op, xpath, match);
689 xmlNode *child = NULL;
690 xmlNode *match_child = NULL;
692 match_child = match->children;
695 while ((match_child != NULL)
697 match_child = match_child->next;
702 if (match_child != NULL) {
703 crm_trace(
"Adding %s at position %d", child->name, position);
704 xmlAddPrevSibling(match_child, child);
707 crm_trace(
"Adding %s at position %d (end)",
708 child->name, position);
716 xmlNode *match_child = NULL;
724 match_child = match->parent->children;
726 while ((match_child != NULL)
728 match_child = match_child->next;
731 crm_trace(
"Moving %s to position %d (was %d, prev %p, %s %p)",
732 match->name, position,
734 match->prev, (match_child?
"next":
"last"),
735 (match_child? match_child : match->parent->last));
738 xmlAddPrevSibling(match_child, match);
742 xmlAddNextSibling(match->parent->last, match);
746 crm_trace(
"%s is already in position %d",
747 match->name, position);
751 crm_err(
"Moved %s.%s to position %d instead of %d (%p)",
752 match->name, pcmk__xe_id(match),
754 position, match->prev);
760 g_list_free_full(change_objs, free);
770 const char *digest = NULL;
772 if (patchset == NULL) {
786 if (digest != NULL) {
797 crm_err(
"Unknown patch format: %d", format);
805 if ((rc ==
pcmk_ok) && (digest != NULL)) {
806 char *new_digest = NULL;
810 crm_info(
"v%d digest mis-match: expected %s, calculated %s",
811 format, digest, new_digest);
823 crm_trace(
"v%d digest matched: expected %s, calculated %s",
824 format, digest, new_digest);
837 char *element_regex = NULL;
845 crm_warn(
"Unknown patch format: %d", format);
849 CRM_CHECK(element_xpath != NULL,
return false);
void xml_acl_disable(xmlNode *xml)
const char * pcmk__cib_abs_xpath_for(const char *element)
const char * pcmk_cib_parent_name_for(const char *element_name)
Get the parent element name of a given CIB element name.
#define pcmk__assert_alloc(nmemb, size)
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
G_GNUC_INTERNAL int pcmk__xml_position(const xmlNode *xml, enum pcmk__xml_flags ignore_if_set)
char * pcmk__digest_xml(xmlNode *input, bool filter)
#define crm_log_xml_info(xml, text)
#define crm_info(fmt, args...)
#define crm_warn(fmt, args...)
#define CRM_LOG_ASSERT(expr)
#define crm_notice(fmt, args...)
#define CRM_CHECK(expr, failure_action)
#define crm_debug(fmt, args...)
#define crm_err(fmt, args...)
#define crm_trace(fmt, args...)
#define pcmk__log_xml_patchset(level, patchset)
#define pcmk__if_tracing(if_action, else_action)
#define PCMK_VALUE_DELETE
#define PCMK_VALUE_MODIFY
#define PCMK_VALUE_CREATE
bool pcmk__cib_element_in_patchset(const xmlNode *patchset, const char *element)
xmlNode * xml_create_patchset(int format, xmlNode *source, xmlNode *target, bool *config_changed, bool manage_version)
bool xml_patch_versions(const xmlNode *patchset, int add[3], int del[3])
struct xml_change_obj_s xml_change_obj_t
void patchset_process_digest(xmlNode *patch, xmlNode *source, xmlNode *target, bool with_digest)
int xml_apply_patchset(xmlNode *xml, xmlNode *patchset, bool check_version)
pcmk__action_result_t result
int pcmk_rc2legacy(int rc)
#define pcmk_err_diff_failed
#define pcmk__assert(expr)
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
int position
Position of the deleted node among its siblings.
gchar * path
XPath expression identifying the deleted node.
GList * deleted_objs
XML nodes marked as deleted (list of pcmk__deleted_xml_t)
uint32_t flags
Group of enum pcmk__xml_flags
Wrappers for and extensions to libxml2.
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
void pcmk__xe_remove_matching_attrs(xmlNode *element, bool force, bool(*match)(xmlAttrPtr, void *), void *user_data)
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
xmlNode * pcmk__xe_next(const xmlNode *node, const char *element_name)
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
bool pcmk__xml_doc_all_flags_set(const xmlDoc *xml, uint32_t flags)
@ pcmk__xf_deleted
Node was deleted (set for attribute only)
@ pcmk__xf_created
Node was created.
@ pcmk__xf_skip
Skip counting this node when getting a node's position among siblings.
@ pcmk__xf_moved
Node was moved.
void pcmk__xml_free(xmlNode *xml)
void save_xml_to_file(const xmlNode *xml, const char *desc, const char *filename)
#define PCMK_XA_OPERATION
#define PCMK_XE_CHANGE_LIST
#define PCMK_XA_ADMIN_EPOCH
#define PCMK_XE_CONFIGURATION
#define PCMK_XA_NUM_UPDATES
#define PCMK_XE_CHANGE_ATTR
#define PCMK_XE_CHANGE_RESULT
GString * pcmk__element_xpath(const xmlNode *xml)