13 #include <sys/types.h> 21 #include <libxml/tree.h> 33 add_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);
149 is_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,
179 xml_create_patchset_v2(xmlNode *source, xmlNode *
target)
187 xmlNode *patchset = NULL;
188 const char *vfields[] = {
200 docpriv =
target->doc->_private;
227 for (gIter = docpriv->
deleted_objs; gIter; gIter = gIter->next) {
238 add_xml_changes_to_patchset(
target, patchset);
244 bool *config_changed,
bool manage_version)
246 bool local_config_changed =
false;
252 crm_err(
"Unknown patch format: %d", format);
262 if (config_changed == NULL) {
263 config_changed = &local_config_changed;
265 *config_changed = is_config_change(
target);
267 if (manage_version) {
270 if (*config_changed) {
282 return xml_create_patchset_v2(source,
target);
291 if ((patch == NULL) || (source == NULL) || (
target == NULL)
313 static const char *
const vfields[] = {
329 crm_err(
"Unknown patch format: %d", format);
333 if (source != NULL) {
336 crm_trace(
"Got %d for del[%s]", del[i], vfields[i]);
343 crm_trace(
"Got %d for add[%s]", add[i], vfields[i]);
359 xml_patch_version_check(
const xmlNode *xml,
const xmlNode *patchset)
362 bool changed = FALSE;
364 int this[] = { 0, 0, 0 };
365 int add[] = { 0, 0, 0 };
366 int del[] = { 0, 0, 0 };
368 const char *vfields[] = {
376 crm_trace(
"Got %d for this[%s]",
this[lpc], vfields[lpc]);
385 add[2] =
this[2] + 1;
387 del[lpc] =
this[lpc];
393 if (
this[lpc] < del[lpc]) {
394 crm_debug(
"Current %s is too low (%d.%d.%d < %d.%d.%d --> %d.%d.%d)",
395 vfields[lpc],
this[0],
this[1],
this[2],
396 del[0], del[1], del[2], add[0], add[1], add[2]);
399 }
else if (
this[lpc] > del[lpc]) {
400 crm_info(
"Current %s is too high (%d.%d.%d > %d.%d.%d --> %d.%d.%d) %p",
401 vfields[lpc],
this[0],
this[1],
this[2],
402 del[0], del[1], del[2], add[0], add[1], add[2], patchset);
409 if (add[lpc] > del[lpc]) {
415 crm_notice(
"Versions did not change in patch %d.%d.%d",
416 add[0], add[1], add[2]);
420 crm_debug(
"Can apply patch %d.%d.%d to %d.%d.%d",
421 add[0], add[1], add[2],
this[0],
this[1],
this[2]);
427 first_matching_xml_child(
const xmlNode *
parent,
const char *
name,
428 const char *
id,
int position)
430 xmlNode *cIter = NULL;
432 for (cIter = pcmk__xml_first_child(
parent); cIter != NULL;
433 cIter = pcmk__xml_next(cIter)) {
434 if (strcmp((
const char *) cIter->name,
name) != 0) {
437 const char *cid = pcmk__xe_id(cIter);
439 if ((cid == NULL) || (strcmp(cid,
id) != 0)) {
445 if ((cIter->type == XML_COMMENT_NODE)
470 search_v2_xpath(
const xmlNode *top,
const char *key,
int target_position)
472 xmlNode *
target = (xmlNode *) top->doc;
473 const char *current = key;
483 key_len = strlen(key);
496 rc = sscanf(current,
"/%[^/]%s", section, remainder);
499 int f = sscanf(section,
"%[^[][@" PCMK_XA_ID "='%[^']", tag,
id);
500 int current_position = -1;
505 if ((rc == 1) && (target_position >= 0)) {
506 current_position = target_position;
527 }
while ((rc == 2) &&
target);
531 (
path = (
char *) xmlGetNodePath(
target)), key);
544 typedef struct xml_change_obj_s {
545 const xmlNode *change;
550 sort_change_obj_by_position(gconstpointer a, gconstpointer b)
560 if (position_a < position_b) {
563 }
else if (position_a > position_b) {
580 apply_v2_patchset(xmlNode *xml,
const xmlNode *patchset)
583 const xmlNode *change = NULL;
584 GList *change_objs = NULL;
587 for (change = pcmk__xml_first_child(patchset); change != NULL;
588 change = pcmk__xml_next(change)) {
589 xmlNode *match = NULL;
598 crm_trace(
"Processing %s %s", change->name, op);
606 match = search_v2_xpath(xml, xpath, position);
607 crm_trace(
"Performing %s on %s with %p", op, xpath, match);
610 crm_debug(
"No %s match for %s in %p", op, xpath, xml->doc);
613 }
else if (match == NULL) {
614 crm_err(
"No %s match for %s in %p", op, xpath, xml->doc);
624 change_obj->change = change;
625 change_obj->match = match;
627 change_objs = g_list_append(change_objs, change_obj);
631 if ((match->parent != NULL) && (match->parent->last != NULL)) {
632 xmlAddNextSibling(match->parent->last, match);
643 const xmlNode *attrs = pcmk__xml_first_child(child);
651 for (xmlAttrPtr pIter = pcmk__xe_first_attr(attrs); pIter != NULL;
652 pIter = pIter->next) {
653 const char *
name = (
const char *) pIter->name;
654 const char *value = pcmk__xml_attr_value(pIter);
660 crm_err(
"Unknown operation: %s", op);
666 change_objs = g_list_sort(change_objs, sort_change_obj_by_position);
668 for (gIter = change_objs; gIter; gIter = gIter->next) {
670 xmlNode *match = change_obj->match;
671 const char *op = NULL;
672 const char *xpath = NULL;
674 change = change_obj->change;
679 crm_trace(
"Continue performing %s on %s with %p", op, xpath, match);
683 xmlNode *child = NULL;
684 xmlNode *match_child = NULL;
686 match_child = match->children;
689 while ((match_child != NULL)
691 match_child = match_child->next;
696 if (match_child != NULL) {
697 crm_trace(
"Adding %s at position %d", child->name, position);
698 xmlAddPrevSibling(match_child, child);
701 crm_trace(
"Adding %s at position %d (end)",
702 child->name, position);
710 xmlNode *match_child = NULL;
718 match_child = match->parent->children;
720 while ((match_child != NULL)
722 match_child = match_child->next;
725 crm_trace(
"Moving %s to position %d (was %d, prev %p, %s %p)",
726 match->name, position,
728 match->prev, (match_child?
"next":
"last"),
729 (match_child? match_child : match->parent->last));
732 xmlAddPrevSibling(match_child, match);
736 xmlAddNextSibling(match->parent->last, match);
740 crm_trace(
"%s is already in position %d",
741 match->name, position);
745 crm_err(
"Moved %s.%s to position %d instead of %d (%p)",
746 match->name, pcmk__xe_id(match),
748 position, match->prev);
754 g_list_free_full(change_objs, free);
764 const char *digest = NULL;
766 if (patchset == NULL) {
780 if (digest != NULL) {
791 crm_err(
"Unknown patch format: %d", format);
799 if ((rc ==
pcmk_ok) && (digest != NULL)) {
800 char *new_digest = NULL;
804 crm_info(
"v%d digest mis-match: expected %s, calculated %s",
805 format, digest, new_digest);
817 crm_trace(
"v%d digest matched: expected %s, calculated %s",
818 format, digest, new_digest);
831 char *element_regex = NULL;
839 crm_warn(
"Unknown patch format: %d", format);
843 CRM_CHECK(element_xpath != NULL,
return false);
#define CRM_CHECK(expr, failure_action)
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
#define crm_notice(fmt, args...)
void patchset_process_digest(xmlNode *patch, xmlNode *source, xmlNode *target, bool with_digest)
#define pcmk__if_tracing(if_action, else_action)
bool pcmk__cib_element_in_patchset(const xmlNode *patchset, const char *element)
int pcmk_rc2legacy(int rc)
void save_xml_to_file(const xmlNode *xml, const char *desc, const char *filename)
#define PCMK_XE_CHANGE_ATTR
#define PCMK_VALUE_CREATE
G_GNUC_INTERNAL int pcmk__xml_position(const xmlNode *xml, enum xml_private_flags ignore_if_set)
#define PCMK_XA_NUM_UPDATES
#define PCMK_XE_CHANGE_LIST
#define CRM_LOG_ASSERT(expr)
char * pcmk__digest_xml(xmlNode *input, bool filter)
#define PCMK_XA_OPERATION
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
void pcmk__xml_free(xmlNode *xml)
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
#define crm_warn(fmt, args...)
#define pcmk_err_diff_failed
#define crm_debug(fmt, args...)
struct xml_change_obj_s xml_change_obj_t
#define PCMK_VALUE_MODIFY
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
#define PCMK_XE_CHANGE_RESULT
#define crm_trace(fmt, args...)
#define PCMK_VALUE_DELETE
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Wrappers for and extensions to libxml2.
bool xml_document_dirty(xmlNode *xml)
const char * pcmk_cib_parent_name_for(const char *element_name)
Get the parent element name of a given CIB element name.
#define PCMK_XE_CONFIGURATION
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
xmlNode * xml_create_patchset(int format, xmlNode *source, xmlNode *target, bool *config_changed, bool manage_version)
const char * pcmk__cib_abs_xpath_for(const char *element)
xmlNode * pcmk__xe_next(const xmlNode *node, const char *element_name)
#define pcmk__assert(expr)
pcmk__action_result_t result
#define crm_err(fmt, args...)
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
void xml_acl_disable(xmlNode *xml)
#define crm_log_xml_info(xml, text)
bool xml_patch_versions(const xmlNode *patchset, int add[3], int del[3])
GString * pcmk__element_xpath(const xmlNode *xml)
#define pcmk__log_xml_patchset(level, patchset)
int xml_apply_patchset(xmlNode *xml, xmlNode *patchset, bool check_version)
#define PCMK_XA_ADMIN_EPOCH
#define pcmk__assert_alloc(nmemb, size)
#define crm_info(fmt, args...)
void pcmk__xe_remove_matching_attrs(xmlNode *element, bool(*match)(xmlAttrPtr, void *), void *user_data)
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.