pacemaker  2.0.4-2deceaa
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cib_ops.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2018 Andrew Beekhof <andrew@beekhof.net>
3  *
4  * This source code is licensed under the GNU Lesser General Public License
5  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
6  */
7 
8 #include <crm_internal.h>
9 
10 #include <stdio.h>
11 #include <unistd.h>
12 #include <stdlib.h>
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <time.h>
16 
17 #include <sys/param.h>
18 #include <sys/types.h>
19 
20 #include <crm/crm.h>
21 #include <crm/cib/internal.h>
22 #include <crm/msg_xml.h>
23 
24 #include <crm/common/xml.h>
25 
26 int
27 cib_process_query(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
28  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
29 {
30  xmlNode *obj_root = NULL;
31  int result = pcmk_ok;
32 
33  crm_trace("Processing \"%s\" event for section=%s", op, crm_str(section));
34 
35  if (options & cib_xpath) {
36  return cib_process_xpath(op, options, section, req, input,
37  existing_cib, result_cib, answer);
38  }
39 
40  CRM_CHECK(*answer == NULL, free_xml(*answer));
41  *answer = NULL;
42 
43  if (safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
44  section = NULL;
45  }
46 
47  obj_root = get_object_root(section, existing_cib);
48 
49  if (obj_root == NULL) {
50  result = -ENXIO;
51 
52  } else if (options & cib_no_children) {
53  const char *tag = TYPE(obj_root);
54  xmlNode *shallow = create_xml_node(*answer, tag);
55 
56  copy_in_properties(shallow, obj_root);
57  *answer = shallow;
58 
59  } else {
60  *answer = obj_root;
61  }
62 
63  if (result == pcmk_ok && *answer == NULL) {
64  crm_err("Error creating query response");
65  result = -ENOMSG;
66  }
67 
68  return result;
69 }
70 
71 int
72 cib_process_erase(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
73  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
74 {
75  int result = pcmk_ok;
76 
77  crm_trace("Processing \"%s\" event", op);
78  *answer = NULL;
79  free_xml(*result_cib);
80  *result_cib = createEmptyCib(0);
81 
82  copy_in_properties(*result_cib, existing_cib);
83  cib_update_counter(*result_cib, XML_ATTR_GENERATION_ADMIN, FALSE);
84 
85  return result;
86 }
87 
88 int
89 cib_process_upgrade(const char *op, int options, const char *section, xmlNode * req,
90  xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
91  xmlNode ** answer)
92 {
93  int rc = 0;
94  int new_version = 0;
95  int current_version = 0;
96  int max_version = 0;
97  const char *max = crm_element_value(req, F_CIB_SCHEMA_MAX);
98  const char *value = crm_element_value(existing_cib, XML_ATTR_VALIDATION);
99 
100  *answer = NULL;
101  crm_trace("Processing \"%s\" event with max=%s", op, max);
102 
103  if (value != NULL) {
104  current_version = get_schema_version(value);
105  }
106 
107  if (max) {
108  max_version = get_schema_version(max);
109  }
110 
111  rc = update_validation(result_cib, &new_version, max_version, TRUE,
112  !(options & cib_verbose));
113  if (new_version > current_version) {
114  cib_update_counter(*result_cib, XML_ATTR_GENERATION_ADMIN, FALSE);
115  cib_update_counter(*result_cib, XML_ATTR_GENERATION, TRUE);
116  cib_update_counter(*result_cib, XML_ATTR_NUMUPDATES, TRUE);
117  return pcmk_ok;
118  }
119 
120  return rc;
121 }
122 
123 int
124 cib_process_bump(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
125  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
126 {
127  int result = pcmk_ok;
128 
129  crm_trace("Processing \"%s\" event for epoch=%s",
130  op, crm_str(crm_element_value(existing_cib, XML_ATTR_GENERATION)));
131 
132  *answer = NULL;
133  cib_update_counter(*result_cib, XML_ATTR_GENERATION, FALSE);
134 
135  return result;
136 }
137 
138 int
139 cib_update_counter(xmlNode * xml_obj, const char *field, gboolean reset)
140 {
141  char *new_value = NULL;
142  char *old_value = NULL;
143  int int_value = -1;
144 
145  if (reset == FALSE && crm_element_value(xml_obj, field) != NULL) {
146  old_value = crm_element_value_copy(xml_obj, field);
147  }
148  if (old_value != NULL) {
149  int_value = atoi(old_value);
150  new_value = crm_itoa(++int_value);
151  } else {
152  new_value = strdup("1");
153  }
154 
155  crm_trace("%s %d(%s)->%s", field, int_value, crm_str(old_value), crm_str(new_value));
156  crm_xml_add(xml_obj, field, new_value);
157 
158  free(new_value);
159  free(old_value);
160 
161  return pcmk_ok;
162 }
163 
164 int
165 cib_process_replace(const char *op, int options, const char *section, xmlNode * req,
166  xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
167  xmlNode ** answer)
168 {
169  const char *tag = NULL;
170  int result = pcmk_ok;
171 
172  crm_trace("Processing \"%s\" event for section=%s", op, crm_str(section));
173 
174  if (options & cib_xpath) {
175  return cib_process_xpath(op, options, section, req, input,
176  existing_cib, result_cib, answer);
177  }
178 
179  *answer = NULL;
180 
181  if (input == NULL) {
182  return -EINVAL;
183  }
184 
185  tag = crm_element_name(input);
186 
187  if (safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
188  section = NULL;
189 
190  } else if (safe_str_eq(tag, section)) {
191  section = NULL;
192  }
193 
194  if (safe_str_eq(tag, XML_TAG_CIB)) {
195  int updates = 0;
196  int epoch = 0;
197  int admin_epoch = 0;
198 
199  int replace_updates = 0;
200  int replace_epoch = 0;
201  int replace_admin_epoch = 0;
202 
203  const char *reason = NULL;
204  const char *peer = crm_element_value(req, F_ORIG);
205  const char *digest = crm_element_value(req, XML_ATTR_DIGEST);
206 
207  if (digest) {
208  const char *version = crm_element_value(req, XML_ATTR_CRM_VERSION);
209  char *digest_verify = calculate_xml_versioned_digest(input, FALSE, TRUE,
210  version ? version :
212 
213  if (safe_str_neq(digest_verify, digest)) {
214  crm_err("Digest mis-match on replace from %s: %s vs. %s (expected)", peer,
215  digest_verify, digest);
216  reason = "digest mismatch";
217 
218  } else {
219  crm_info("Digest matched on replace from %s: %s", peer, digest);
220  }
221  free(digest_verify);
222 
223  } else {
224  crm_trace("No digest to verify");
225  }
226 
227  cib_version_details(existing_cib, &admin_epoch, &epoch, &updates);
228  cib_version_details(input, &replace_admin_epoch, &replace_epoch, &replace_updates);
229 
230  if (replace_admin_epoch < admin_epoch) {
231  reason = XML_ATTR_GENERATION_ADMIN;
232 
233  } else if (replace_admin_epoch > admin_epoch) {
234  /* no more checks */
235 
236  } else if (replace_epoch < epoch) {
237  reason = XML_ATTR_GENERATION;
238 
239  } else if (replace_epoch > epoch) {
240  /* no more checks */
241 
242  } else if (replace_updates < updates) {
243  reason = XML_ATTR_NUMUPDATES;
244  }
245 
246  if (reason != NULL) {
247  crm_info("Replacement %d.%d.%d from %s not applied to %d.%d.%d:"
248  " current %s is greater than the replacement",
249  replace_admin_epoch, replace_epoch,
250  replace_updates, peer, admin_epoch, epoch, updates, reason);
251  result = -pcmk_err_old_data;
252  } else {
253  crm_info("Replaced %d.%d.%d with %d.%d.%d from %s",
254  admin_epoch, epoch, updates,
255  replace_admin_epoch, replace_epoch, replace_updates, peer);
256  }
257 
258  free_xml(*result_cib);
259  *result_cib = copy_xml(input);
260 
261  } else {
262  xmlNode *obj_root = NULL;
263  gboolean ok = TRUE;
264 
265  obj_root = get_object_root(section, *result_cib);
266  ok = replace_xml_child(NULL, obj_root, input, FALSE);
267  if (ok == FALSE) {
268  crm_trace("No matching object to replace");
269  result = -ENXIO;
270  }
271  }
272 
273  return result;
274 }
275 
276 int
277 cib_process_delete(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
278  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
279 {
280  xmlNode *obj_root = NULL;
281 
282  crm_trace("Processing \"%s\" event", op);
283 
284  if (options & cib_xpath) {
285  return cib_process_xpath(op, options, section, req, input,
286  existing_cib, result_cib, answer);
287  }
288 
289  if (input == NULL) {
290  crm_err("Cannot perform modification with no data");
291  return -EINVAL;
292  }
293 
294  obj_root = get_object_root(section, *result_cib);
295  if(safe_str_eq(crm_element_name(input), section)) {
296  xmlNode *child = NULL;
297  for(child = __xml_first_child(input); child; child = __xml_next(child)) {
298  if (replace_xml_child(NULL, obj_root, child, TRUE) == FALSE) {
299  crm_trace("No matching object to delete: %s=%s", child->name, ID(child));
300  }
301  }
302 
303  } else if (replace_xml_child(NULL, obj_root, input, TRUE) == FALSE) {
304  crm_trace("No matching object to delete: %s=%s", input->name, ID(input));
305  }
306 
307  return pcmk_ok;
308 }
309 
310 int
311 cib_process_modify(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
312  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
313 {
314  xmlNode *obj_root = NULL;
315 
316  crm_trace("Processing \"%s\" event", op);
317 
318  if (options & cib_xpath) {
319  return cib_process_xpath(op, options, section, req, input,
320  existing_cib, result_cib, answer);
321  }
322 
323  if (input == NULL) {
324  crm_err("Cannot perform modification with no data");
325  return -EINVAL;
326  }
327 
328  obj_root = get_object_root(section, *result_cib);
329  if (obj_root == NULL) {
330  xmlNode *tmp_section = NULL;
331  const char *path = get_object_parent(section);
332 
333  if (path == NULL) {
334  return -EINVAL;
335  }
336 
337  tmp_section = create_xml_node(NULL, section);
338  cib_process_xpath(CIB_OP_CREATE, 0, path, NULL, tmp_section, NULL, result_cib, answer);
339  free_xml(tmp_section);
340 
341  obj_root = get_object_root(section, *result_cib);
342  }
343 
344  CRM_CHECK(obj_root != NULL, return -EINVAL);
345 
346  if (update_xml_child(obj_root, input) == FALSE) {
347  if (options & cib_can_create) {
348  add_node_copy(obj_root, input);
349  } else {
350  return -ENXIO;
351  }
352  }
353 
354  if(options & cib_mixed_update) {
355  int max = 0, lpc;
356  xmlXPathObjectPtr xpathObj = xpath_search(*result_cib, "//@__delete__");
357 
358  if (xpathObj) {
359  max = numXpathResults(xpathObj);
360  crm_log_xml_trace(*result_cib, "Mixed result");
361  }
362 
363  for (lpc = 0; lpc < max; lpc++) {
364  xmlNode *match = getXpathResult(xpathObj, lpc);
365  xmlChar *match_path = xmlGetNodePath(match);
366 
367  crm_debug("Destroying %s", match_path);
368  free(match_path);
369  free_xml(match);
370  }
371 
372  freeXpathObject(xpathObj);
373  }
374  return pcmk_ok;
375 }
376 
377 static int
378 update_cib_object(xmlNode * parent, xmlNode * update)
379 {
380  int result = pcmk_ok;
381  xmlNode *target = NULL;
382  xmlNode *a_child = NULL;
383  const char *replace = NULL;
384  const char *object_id = NULL;
385  const char *object_name = NULL;
386 
387  CRM_CHECK(update != NULL, return -EINVAL);
388  CRM_CHECK(parent != NULL, return -EINVAL);
389 
390  object_name = crm_element_name(update);
391  CRM_CHECK(object_name != NULL, return -EINVAL);
392 
393  object_id = ID(update);
394  crm_trace("Processing: <%s id=%s>", crm_str(object_name), crm_str(object_id));
395 
396  if (object_id == NULL) {
397  /* placeholder object */
398  target = find_xml_node(parent, object_name, FALSE);
399 
400  } else {
401  target = find_entity(parent, object_name, object_id);
402  }
403 
404  if (target == NULL) {
405  target = create_xml_node(parent, object_name);
406  }
407 
408  crm_trace("Found node <%s id=%s> to update", crm_str(object_name), crm_str(object_id));
409 
410  replace = crm_element_value(update, XML_CIB_ATTR_REPLACE);
411  if (replace != NULL) {
412  xmlNode *remove = NULL;
413  int last = 0, lpc = 0, len = 0;
414 
415  len = strlen(replace);
416  while (lpc <= len) {
417  if (replace[lpc] == ',' || replace[lpc] == 0) {
418  char *replace_item = NULL;
419 
420  if (last == lpc) {
421  /* nothing to do */
422  last = lpc + 1;
423  goto incr;
424  }
425 
426  replace_item = strndup(replace + last, lpc - last);
427  remove = find_xml_node(target, replace_item, FALSE);
428  if (remove != NULL) {
429  crm_trace("Replacing node <%s> in <%s>",
430  replace_item, crm_element_name(target));
431  free_xml(remove);
432  remove = NULL;
433  }
434  free(replace_item);
435  last = lpc + 1;
436  }
437  incr:
438  lpc++;
439  }
442  }
443 
444  copy_in_properties(target, update);
445 
446  crm_trace("Processing children of <%s id=%s>", crm_str(object_name), crm_str(object_id));
447 
448  for (a_child = __xml_first_child(update); a_child != NULL; a_child = __xml_next(a_child)) {
449  int tmp_result = 0;
450 
451  crm_trace("Updating child <%s id=%s>", crm_element_name(a_child), ID(a_child));
452 
453  tmp_result = update_cib_object(target, a_child);
454 
455  /* only the first error is likely to be interesting */
456  if (tmp_result != pcmk_ok) {
457  crm_err("Error updating child <%s id=%s>", crm_element_name(a_child), ID(a_child));
458 
459  if (result == pcmk_ok) {
460  result = tmp_result;
461  }
462  }
463  }
464 
465  crm_trace("Finished with <%s id=%s>", crm_str(object_name), crm_str(object_id));
466 
467  return result;
468 }
469 
470 static int
471 add_cib_object(xmlNode * parent, xmlNode * new_obj)
472 {
473  int result = pcmk_ok;
474  const char *object_name = NULL;
475  const char *object_id = NULL;
476  xmlNode *equiv_node = NULL;
477 
478  if (new_obj != NULL) {
479  object_name = crm_element_name(new_obj);
480  }
481  object_id = crm_element_value(new_obj, XML_ATTR_ID);
482 
483  crm_trace("Processing: <%s id=%s>", crm_str(object_name), crm_str(object_id));
484 
485  if (new_obj == NULL || object_name == NULL) {
486  result = -EINVAL;
487 
488  } else if (parent == NULL) {
489  result = -EINVAL;
490 
491  } else if (object_id == NULL) {
492  /* placeholder object */
493  equiv_node = find_xml_node(parent, object_name, FALSE);
494 
495  } else {
496  equiv_node = find_entity(parent, object_name, object_id);
497  }
498 
499  if (result != pcmk_ok) {
500  ; /* do nothing */
501 
502  } else if (equiv_node != NULL) {
503  result = -EEXIST;
504 
505  } else {
506  result = update_cib_object(parent, new_obj);
507  }
508 
509  return result;
510 }
511 
512 int
513 cib_process_create(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
514  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
515 {
516  xmlNode *failed = NULL;
517  int result = pcmk_ok;
518  xmlNode *update_section = NULL;
519 
520  crm_trace("Processing \"%s\" event for section=%s", op, crm_str(section));
521  if (safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
522  section = NULL;
523 
524  } else if (safe_str_eq(XML_TAG_CIB, section)) {
525  section = NULL;
526 
527  } else if (safe_str_eq(crm_element_name(input), XML_TAG_CIB)) {
528  section = NULL;
529  }
530 
531  CRM_CHECK(strcasecmp(CIB_OP_CREATE, op) == 0, return -EINVAL);
532 
533  if (input == NULL) {
534  crm_err("Cannot perform modification with no data");
535  return -EINVAL;
536  }
537 
538  if (section == NULL) {
539  return cib_process_modify(op, options, section, req, input, existing_cib, result_cib,
540  answer);
541  }
542 
543  failed = create_xml_node(NULL, XML_TAG_FAILED);
544 
545  update_section = get_object_root(section, *result_cib);
546  if (safe_str_eq(crm_element_name(input), section)) {
547  xmlNode *a_child = NULL;
548 
549  for (a_child = __xml_first_child(input); a_child != NULL; a_child = __xml_next(a_child)) {
550  result = add_cib_object(update_section, a_child);
551  if (update_results(failed, a_child, op, result)) {
552  break;
553  }
554  }
555 
556  } else {
557  result = add_cib_object(update_section, input);
558  update_results(failed, input, op, result);
559  }
560 
561  if ((result == pcmk_ok) && xml_has_children(failed)) {
562  result = -EINVAL;
563  }
564 
565  if (result != pcmk_ok) {
566  crm_log_xml_err(failed, "CIB Update failures");
567  *answer = failed;
568 
569  } else {
570  free_xml(failed);
571  }
572 
573  return result;
574 }
575 
576 int
577 cib_process_diff(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
578  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
579 {
580  const char *originator = NULL;
581 
582  if (req != NULL) {
583  originator = crm_element_value(req, F_ORIG);
584  }
585 
586  crm_trace("Processing \"%s\" event from %s %s",
587  op, originator, is_set(options, cib_force_diff)?"(global update)":"");
588 
589  free_xml(*result_cib);
590  *result_cib = copy_xml(existing_cib);
591  return xml_apply_patchset(*result_cib, input, TRUE);
592 }
593 
594 gboolean
595 cib_config_changed(xmlNode * last, xmlNode * next, xmlNode ** diff)
596 {
597  int lpc = 0, max = 0;
598  gboolean config_changes = FALSE;
599  xmlXPathObject *xpathObj = NULL;
600  int format = 1;
601 
602  CRM_ASSERT(diff != NULL);
603 
604  if (*diff == NULL && last != NULL && next != NULL) {
605  *diff = diff_xml_object(last, next, FALSE);
606  }
607 
608  if (*diff == NULL) {
609  goto done;
610  }
611 
612  crm_element_value_int(*diff, "format", &format);
613  /* This function only applies to v1 diffs. */
614  CRM_LOG_ASSERT(format == 1);
615 
616  xpathObj = xpath_search(*diff, "//" XML_CIB_TAG_CONFIGURATION);
617  if (numXpathResults(xpathObj) > 0) {
618  config_changes = TRUE;
619  goto done;
620  }
621  freeXpathObject(xpathObj);
622 
623  /*
624  * Do not check XML_TAG_DIFF_ADDED "//" XML_TAG_CIB
625  * This always contains every field and would produce a false positive
626  * every time if the checked value existed
627  */
628  xpathObj = xpath_search(*diff, "//" XML_TAG_DIFF_REMOVED "//" XML_TAG_CIB);
629  max = numXpathResults(xpathObj);
630 
631  for (lpc = 0; lpc < max; lpc++) {
632  xmlNode *top = getXpathResult(xpathObj, lpc);
633 
634  if (crm_element_value(top, XML_ATTR_GENERATION) != NULL) {
635  config_changes = TRUE;
636  goto done;
637  }
638  if (crm_element_value(top, XML_ATTR_GENERATION_ADMIN) != NULL) {
639  config_changes = TRUE;
640  goto done;
641  }
642 
643  if (crm_element_value(top, XML_ATTR_VALIDATION) != NULL) {
644  config_changes = TRUE;
645  goto done;
646  }
647  if (crm_element_value(top, XML_ATTR_CRM_VERSION) != NULL) {
648  config_changes = TRUE;
649  goto done;
650  }
651  if (crm_element_value(top, "remote-clear-port") != NULL) {
652  config_changes = TRUE;
653  goto done;
654  }
655  if (crm_element_value(top, "remote-tls-port") != NULL) {
656  config_changes = TRUE;
657  goto done;
658  }
659  }
660 
661  done:
662  freeXpathObject(xpathObj);
663  return config_changes;
664 }
665 
666 int
667 cib_process_xpath(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
668  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
669 {
670  int lpc = 0;
671  int max = 0;
672  int rc = pcmk_ok;
673  gboolean is_query = safe_str_eq(op, CIB_OP_QUERY);
674 
675  xmlXPathObjectPtr xpathObj = NULL;
676 
677  crm_trace("Processing \"%s\" event", op);
678 
679  if (is_query) {
680  xpathObj = xpath_search(existing_cib, section);
681  } else {
682  xpathObj = xpath_search(*result_cib, section);
683  }
684 
685  max = numXpathResults(xpathObj);
686 
687  if (max < 1 && safe_str_eq(op, CIB_OP_DELETE)) {
688  crm_debug("%s was already removed", section);
689 
690  } else if (max < 1) {
691  crm_debug("%s: %s does not exist", op, section);
692  rc = -ENXIO;
693 
694  } else if (is_query) {
695  if (max > 1) {
696  *answer = create_xml_node(NULL, "xpath-query");
697  }
698  }
699 
700  if (safe_str_eq(op, CIB_OP_DELETE) && (options & cib_multiple)) {
701  dedupXpathResults(xpathObj);
702  }
703 
704  for (lpc = 0; lpc < max; lpc++) {
705  xmlChar *path = NULL;
706  xmlNode *match = getXpathResult(xpathObj, lpc);
707 
708  if (match == NULL) {
709  continue;
710  }
711 
712  path = xmlGetNodePath(match);
713  crm_debug("Processing %s op for %s with %s", op, section, path);
714  free(path);
715 
716  if (safe_str_eq(op, CIB_OP_DELETE)) {
717  if (match == *result_cib) {
718  /* Attempting to delete the whole "/cib" */
719  crm_warn("Cannot perform %s for %s: The xpath is addressing the whole /cib", op, section);
720  rc = -EINVAL;
721  break;
722  }
723 
724  free_xml(match);
725  if ((options & cib_multiple) == 0) {
726  break;
727  }
728 
729  } else if (safe_str_eq(op, CIB_OP_MODIFY)) {
730  if (update_xml_child(match, input) == FALSE) {
731  rc = -ENXIO;
732  } else if ((options & cib_multiple) == 0) {
733  break;
734  }
735 
736  } else if (safe_str_eq(op, CIB_OP_CREATE)) {
737  add_node_copy(match, input);
738  break;
739 
740  } else if (safe_str_eq(op, CIB_OP_QUERY)) {
741 
742  if (options & cib_no_children) {
743  const char *tag = TYPE(match);
744  xmlNode *shallow = create_xml_node(*answer, tag);
745 
746  copy_in_properties(shallow, match);
747 
748  if (*answer == NULL) {
749  *answer = shallow;
750  }
751 
752  } else if (options & cib_xpath_address) {
753  char *path = NULL;
754  xmlNode *parent = match;
755 
756  while (parent && parent->type == XML_ELEMENT_NODE) {
757  const char *id = crm_element_value(parent, XML_ATTR_ID);
758  char *new_path = NULL;
759 
760  if (id) {
761  new_path = crm_strdup_printf("/%s[@id='%s']%s",
762  parent->name, id,
763  (path? path : ""));
764  } else {
765  new_path = crm_strdup_printf("/%s%s", parent->name,
766  (path? path : ""));
767  }
768  free(path);
769  path = new_path;
770  parent = parent->parent;
771  }
772  crm_trace("Got: %s", path);
773 
774  if (*answer == NULL) {
775  *answer = create_xml_node(NULL, "xpath-query");
776  }
777  parent = create_xml_node(*answer, "xpath-query-path");
778  crm_xml_add(parent, XML_ATTR_ID, path);
779  free(path);
780 
781  } else if (*answer) {
782  add_node_copy(*answer, match);
783 
784  } else {
785  *answer = match;
786  }
787 
788  } else if (safe_str_eq(op, CIB_OP_REPLACE)) {
789  xmlNode *parent = match->parent;
790 
791  free_xml(match);
792  if (input != NULL) {
793  add_node_copy(parent, input);
794  }
795 
796  if ((options & cib_multiple) == 0) {
797  break;
798  }
799  }
800  }
801 
802  freeXpathObject(xpathObj);
803  return rc;
804 }
805 
806 /* remove this function */
807 gboolean
808 update_results(xmlNode * failed, xmlNode * target, const char *operation, int return_code)
809 {
810  xmlNode *xml_node = NULL;
811  gboolean was_error = FALSE;
812  const char *error_msg = NULL;
813 
814  if (return_code != pcmk_ok) {
815  error_msg = pcmk_strerror(return_code);
816 
817  was_error = TRUE;
818  xml_node = create_xml_node(failed, XML_FAIL_TAG_CIB);
819  add_node_copy(xml_node, target);
820 
821  crm_xml_add(xml_node, XML_FAILCIB_ATTR_ID, ID(target));
822  crm_xml_add(xml_node, XML_FAILCIB_ATTR_OBJTYPE, TYPE(target));
823  crm_xml_add(xml_node, XML_FAILCIB_ATTR_OP, operation);
824  crm_xml_add(xml_node, XML_FAILCIB_ATTR_REASON, error_msg);
825 
826  crm_warn("Action %s failed: %s (cde=%d)", operation, error_msg, return_code);
827  }
828 
829  return was_error;
830 }
#define pcmk_err_old_data
Definition: results.h:74
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:233
#define CIB_OP_CREATE
Definition: internal.h:23
xmlNode * find_xml_node(xmlNode *cib, const char *node_path, gboolean must_find)
Definition: xml.c:1764
A dumping ground.
const char * pcmk_strerror(int rc)
Definition: results.c:55
gboolean cib_version_details(xmlNode *cib, int *admin_epoch, int *epoch, int *updates)
Definition: cib_utils.c:73
#define XML_CIB_TAG_SECTION_ALL
Definition: msg_xml.h:137
gboolean safe_str_neq(const char *a, const char *b)
Definition: strings.c:263
gboolean update_results(xmlNode *failed, xmlNode *target, const char *operation, int return_code)
Definition: cib_ops.c:808
#define XML_ATTR_NUMUPDATES
Definition: msg_xml.h:89
int cib_process_delete(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:277
int cib_process_replace(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:165
xmlNode * get_object_root(const char *object_type, xmlNode *the_root)
Definition: cib_utils.c:144
#define CRM_FEATURE_SET
Definition: crm.h:54
#define XML_FAIL_TAG_CIB
Definition: msg_xml.h:129
xmlNode * find_entity(xmlNode *parent, const char *node_name, const char *id)
Definition: xml.c:1829
int cib_process_erase(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:72
int cib_process_bump(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:124
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:316
int get_schema_version(const char *name)
Definition: schemas.c:1030
int cib_update_counter(xmlNode *xml_obj, const char *field, gboolean reset)
Definition: cib_ops.c:139
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:219
void copy_in_properties(xmlNode *target, xmlNode *src)
Definition: xml.c:1836
int cib_process_xpath(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:667
void dedupXpathResults(xmlXPathObjectPtr xpathObj)
Definition: xpath.c:98
const char * get_object_parent(const char *object_type)
Definition: cib_utils.c:130
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:558
char * strndup(const char *str, size_t len)
#define XML_ATTR_GENERATION
Definition: msg_xml.h:87
#define TYPE(x)
Definition: msg_xml.h:419
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:2142
#define crm_warn(fmt, args...)
Definition: logging.h:364
int rc
Definition: pcmk_fence.c:34
#define crm_debug(fmt, args...)
Definition: logging.h:368
int cib_process_diff(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:577
gboolean cib_config_changed(xmlNode *last, xmlNode *next, xmlNode **diff)
Definition: cib_ops.c:595
int xml_apply_patchset(xmlNode *xml, xmlNode *patchset, bool check_version)
Definition: xml.c:1687
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition: nvpair.c:725
#define XML_TAG_FAILED
Definition: msg_xml.h:77
#define XML_ATTR_ID
Definition: msg_xml.h:96
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:522
gboolean update_xml_child(xmlNode *child, xmlNode *to_update)
Definition: xml.c:4218
#define CIB_OP_QUERY
Definition: internal.h:22
#define crm_trace(fmt, args...)
Definition: logging.h:369
xmlNode * createEmptyCib(int admin_epoch)
Definition: cib_utils.c:160
xmlNode * add_node_copy(xmlNode *new_parent, xmlNode *xml_node)
Definition: xml.c:1954
Wrappers for and extensions to libxml2.
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:1976
#define XML_ATTR_VALIDATION
Definition: msg_xml.h:81
#define F_ORIG
Definition: msg_xml.h:18
#define XML_FAILCIB_ATTR_OP
Definition: msg_xml.h:133
void free_xml(xmlNode *child)
Definition: xml.c:2136
gboolean xml_has_children(const xmlNode *root)
Definition: xml.c:3331
#define XML_FAILCIB_ATTR_OBJTYPE
Definition: msg_xml.h:132
const char * target
Definition: pcmk_fence.c:28
int cib_process_query(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:27
#define XML_TAG_CIB
Definition: msg_xml.h:76
#define crm_log_xml_err(xml, text)
Definition: logging.h:372
#define crm_err(fmt, args...)
Definition: logging.h:363
#define CRM_ASSERT(expr)
Definition: results.h:42
xmlXPathObjectPtr xpath_search(xmlNode *xml_top, const char *path)
Definition: xpath.c:136
Prefer stderr to logs.
Definition: cib_types.h:51
#define XML_FAILCIB_ATTR_REASON
Definition: msg_xml.h:134
#define CIB_OP_DELETE
Definition: internal.h:25
void xml_remove_prop(xmlNode *obj, const char *name)
Definition: xml.c:3340
xmlNode * getXpathResult(xmlXPathObjectPtr xpathObj, int index)
Definition: xpath.c:55
char * calculate_xml_versioned_digest(xmlNode *input, gboolean sort, gboolean do_filter, const char *version)
Calculate and return digest of XML tree.
Definition: digest.c:184
#define CIB_OP_MODIFY
Definition: internal.h:24
#define XML_ATTR_GENERATION_ADMIN
Definition: msg_xml.h:88
#define XML_CIB_ATTR_REPLACE
Definition: msg_xml.h:232
#define crm_str(x)
Definition: logging.h:389
#define XML_ATTR_CRM_VERSION
Definition: msg_xml.h:79
#define CIB_OP_REPLACE
Definition: internal.h:27
#define pcmk_ok
Definition: results.h:67
int update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform, gboolean to_logs)
Update CIB XML to most recent schema version.
Definition: schemas.c:1047
xmlNode * diff_xml_object(xmlNode *left, xmlNode *right, gboolean suppress)
Definition: xml.c:3791
#define crm_log_xml_trace(xml, text)
Definition: logging.h:377
#define XML_TAG_DIFF_REMOVED
Definition: msg_xml.h:368
#define XML_CIB_TAG_CONFIGURATION
Definition: msg_xml.h:138
#define ID(x)
Definition: msg_xml.h:418
#define XML_FAILCIB_ATTR_ID
Definition: msg_xml.h:131
#define safe_str_eq(a, b)
Definition: util.h:65
void freeXpathObject(xmlXPathObjectPtr xpathObj)
Definition: xpath.c:36
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
int cib_process_upgrade(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:89
#define crm_info(fmt, args...)
Definition: logging.h:366
int cib_process_modify(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:311
uint32_t version
Definition: remote.c:147
int cib_process_create(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:513
#define F_CIB_SCHEMA_MAX
Definition: internal.h:59
#define XML_ATTR_DIGEST
Definition: msg_xml.h:80
gboolean replace_xml_child(xmlNode *parent, xmlNode *child, xmlNode *update, gboolean delete_only)
Definition: xml.c:4284