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