pacemaker  3.0.0-d8340737c4
Scalable High-Availability cluster resource manager
cib_ops.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2024 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 <glib.h>
23 #include <libxml/tree.h>
24 
25 #include <crm/crm.h>
26 #include <crm/cib/internal.h>
27 
28 #include <crm/common/xml.h>
30 
31 // @TODO: Free this via crm_exit() when libcib gets merged with libcrmcommon
32 static GHashTable *operation_table = NULL;
33 
34 static const cib__operation_t cib_ops[] = {
35  {
38  },
39  {
44  },
45  {
50  },
51  {
57  },
58  {
63  },
64  {
69  },
70  {
76  },
77  {
80  },
81  {
86  },
87  {
89  },
90  {
92  },
93  {
94  // @COMPAT: Drop cib__op_attr_modifies when we drop legacy mode support
97  },
98  {
100  },
101  {
108  },
109  {
112  },
113  {
115  },
116  {
118  },
119  {
121  },
122  {
128  },
129  {
131  }
132 };
133 
143 int
144 cib__get_operation(const char *op, const cib__operation_t **operation)
145 {
146  pcmk__assert((op != NULL) && (operation != NULL));
147 
148  if (operation_table == NULL) {
149  operation_table = pcmk__strkey_table(NULL, NULL);
150 
151  for (int lpc = 0; lpc < PCMK__NELEM(cib_ops); lpc++) {
152  const cib__operation_t *oper = &(cib_ops[lpc]);
153 
154  g_hash_table_insert(operation_table, (gpointer) oper->name,
155  (gpointer) oper);
156  }
157  }
158 
159  *operation = g_hash_table_lookup(operation_table, op);
160  if (*operation == NULL) {
161  crm_err("Operation %s is invalid", op);
162  return EINVAL;
163  }
164  return pcmk_rc_ok;
165 }
166 
167 int
168 cib_process_query(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
169  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
170 {
171  xmlNode *obj_root = NULL;
172  int result = pcmk_ok;
173 
174  crm_trace("Processing %s for %s section",
175  op, pcmk__s(section, "unspecified"));
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  CRM_CHECK(*answer == NULL, pcmk__xml_free(*answer));
183  *answer = NULL;
184 
185  if (pcmk__str_eq(PCMK__XE_ALL, section, pcmk__str_casei)) {
186  section = NULL;
187  }
188 
189  obj_root = pcmk_find_cib_element(existing_cib, section);
190 
191  if (obj_root == NULL) {
192  result = -ENXIO;
193 
194  } else if (options & cib_no_children) {
195  xmlNode *shallow = pcmk__xe_create(*answer,
196  (const char *) obj_root->name);
197 
198  pcmk__xe_copy_attrs(shallow, obj_root, pcmk__xaf_none);
199  *answer = shallow;
200 
201  } else {
202  *answer = obj_root;
203  }
204 
205  if (result == pcmk_ok && *answer == NULL) {
206  crm_err("Error creating query response");
207  result = -ENOMSG;
208  }
209 
210  return result;
211 }
212 
213 static int
214 update_counter(xmlNode *xml_obj, const char *field, bool reset)
215 {
216  char *new_value = NULL;
217  char *old_value = NULL;
218  int int_value = -1;
219 
220  if (!reset && crm_element_value(xml_obj, field) != NULL) {
221  old_value = crm_element_value_copy(xml_obj, field);
222  }
223  if (old_value != NULL) {
224  int_value = atoi(old_value);
225  new_value = pcmk__itoa(++int_value);
226  } else {
227  new_value = pcmk__str_copy("1");
228  }
229 
230  crm_trace("Update %s from %s to %s",
231  field, pcmk__s(old_value, "unset"), new_value);
232  crm_xml_add(xml_obj, field, new_value);
233 
234  free(new_value);
235  free(old_value);
236 
237  return pcmk_ok;
238 }
239 
240 int
241 cib_process_erase(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
242  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
243 {
244  int result = pcmk_ok;
245 
246  crm_trace("Processing \"%s\" event", op);
247 
248  if (*result_cib != existing_cib) {
249  pcmk__xml_free(*result_cib);
250  }
251  *result_cib = createEmptyCib(0);
252  pcmk__xe_copy_attrs(*result_cib, existing_cib, pcmk__xaf_none);
253  update_counter(*result_cib, PCMK_XA_ADMIN_EPOCH, false);
254  *answer = NULL;
255 
256  return result;
257 }
258 
259 int
260 cib_process_upgrade(const char *op, int options, const char *section, xmlNode * req,
261  xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
262  xmlNode ** answer)
263 {
264  int rc = 0;
265  const char *max_schema = crm_element_value(req, PCMK__XA_CIB_SCHEMA_MAX);
266  const char *original_schema = NULL;
267  const char *new_schema = NULL;
268 
269  *answer = NULL;
270  crm_trace("Processing \"%s\" event with max=%s", op, max_schema);
271 
272  original_schema = crm_element_value(existing_cib, PCMK_XA_VALIDATE_WITH);
273  rc = pcmk__update_schema(result_cib, max_schema, true,
274  !pcmk_is_set(options, cib_verbose));
275  rc = pcmk_rc2legacy(rc);
276  new_schema = crm_element_value(*result_cib, PCMK_XA_VALIDATE_WITH);
277 
278  if (pcmk__cmp_schemas_by_name(new_schema, original_schema) > 0) {
279  update_counter(*result_cib, PCMK_XA_ADMIN_EPOCH, false);
280  update_counter(*result_cib, PCMK_XA_EPOCH, true);
281  update_counter(*result_cib, PCMK_XA_NUM_UPDATES, true);
282  return pcmk_ok;
283  }
284 
285  return rc;
286 }
287 
288 int
289 cib_process_bump(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
290  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
291 {
292  int result = pcmk_ok;
293 
294  crm_trace("Processing %s for epoch='%s'", op,
295  pcmk__s(crm_element_value(existing_cib, PCMK_XA_EPOCH), ""));
296 
297  *answer = NULL;
298  update_counter(*result_cib, PCMK_XA_EPOCH, false);
299 
300  return result;
301 }
302 
303 int
304 cib_process_replace(const char *op, int options, const char *section, xmlNode * req,
305  xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
306  xmlNode ** answer)
307 {
308  int result = pcmk_ok;
309 
310  crm_trace("Processing %s for %s section",
311  op, pcmk__s(section, "unspecified"));
312 
313  if (options & cib_xpath) {
314  return cib_process_xpath(op, options, section, req, input,
315  existing_cib, result_cib, answer);
316  }
317 
318  *answer = NULL;
319 
320  if (input == NULL) {
321  return -EINVAL;
322  }
323 
324  if (pcmk__str_eq(PCMK__XE_ALL, section, pcmk__str_casei)) {
325  section = NULL;
326 
327  } else if (pcmk__xe_is(input, section)) {
328  section = NULL;
329  }
330 
331  if (pcmk__xe_is(input, PCMK_XE_CIB)) {
332  int updates = 0;
333  int epoch = 0;
334  int admin_epoch = 0;
335 
336  int replace_updates = 0;
337  int replace_epoch = 0;
338  int replace_admin_epoch = 0;
339 
340  const char *reason = NULL;
341  const char *peer = crm_element_value(req, PCMK__XA_SRC);
342  const char *digest = crm_element_value(req, PCMK__XA_DIGEST);
343 
344  if (digest) {
345  char *digest_verify = pcmk__digest_xml(input, true);
346 
347  if (!pcmk__str_eq(digest_verify, digest, pcmk__str_casei)) {
348  crm_err("Digest mis-match on replace from %s: %s vs. %s (expected)", peer,
349  digest_verify, digest);
350  reason = "digest mismatch";
351 
352  } else {
353  crm_info("Digest matched on replace from %s: %s", peer, digest);
354  }
355  free(digest_verify);
356 
357  } else {
358  crm_trace("No digest to verify");
359  }
360 
361  cib_version_details(existing_cib, &admin_epoch, &epoch, &updates);
362  cib_version_details(input, &replace_admin_epoch, &replace_epoch, &replace_updates);
363 
364  if (replace_admin_epoch < admin_epoch) {
365  reason = PCMK_XA_ADMIN_EPOCH;
366 
367  } else if (replace_admin_epoch > admin_epoch) {
368  /* no more checks */
369 
370  } else if (replace_epoch < epoch) {
371  reason = PCMK_XA_EPOCH;
372 
373  } else if (replace_epoch > epoch) {
374  /* no more checks */
375 
376  } else if (replace_updates < updates) {
377  reason = PCMK_XA_NUM_UPDATES;
378  }
379 
380  if (reason != NULL) {
381  crm_info("Replacement %d.%d.%d from %s not applied to %d.%d.%d:"
382  " current %s is greater than the replacement",
383  replace_admin_epoch, replace_epoch,
384  replace_updates, peer, admin_epoch, epoch, updates, reason);
386  } else {
387  crm_info("Replaced %d.%d.%d with %d.%d.%d from %s",
388  admin_epoch, epoch, updates,
389  replace_admin_epoch, replace_epoch, replace_updates, peer);
390  }
391 
392  if (*result_cib != existing_cib) {
393  pcmk__xml_free(*result_cib);
394  }
395  *result_cib = pcmk__xml_copy(NULL, input);
396 
397  } else {
398  xmlNode *obj_root = NULL;
399 
400  obj_root = pcmk_find_cib_element(*result_cib, section);
401  result = pcmk__xe_replace_match(obj_root, input);
403  if (result != pcmk_ok) {
404  crm_trace("No matching object to replace");
405  }
406  }
407 
408  return result;
409 }
410 
411 static int
412 delete_child(xmlNode *child, void *userdata)
413 {
414  xmlNode *obj_root = userdata;
415 
416  if (pcmk__xe_delete_match(obj_root, child) != pcmk_rc_ok) {
417  crm_trace("No matching object to delete: %s=%s",
418  child->name, pcmk__xe_id(child));
419  }
420 
421  return pcmk_rc_ok;
422 }
423 
424 int
425 cib_process_delete(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
426  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
427 {
428  xmlNode *obj_root = NULL;
429 
430  crm_trace("Processing \"%s\" event", op);
431 
432  if (options & cib_xpath) {
433  return cib_process_xpath(op, options, section, req, input,
434  existing_cib, result_cib, answer);
435  }
436 
437  if (input == NULL) {
438  crm_err("Cannot perform modification with no data");
439  return -EINVAL;
440  }
441 
442  obj_root = pcmk_find_cib_element(*result_cib, section);
443  if (pcmk__xe_is(input, section)) {
444  pcmk__xe_foreach_child(input, NULL, delete_child, obj_root);
445  } else {
446  delete_child(input, obj_root);
447  }
448 
449  return pcmk_ok;
450 }
451 
452 int
453 cib_process_modify(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
454  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
455 {
456  xmlNode *obj_root = NULL;
457  uint32_t flags = pcmk__xaf_none;
458 
459  crm_trace("Processing \"%s\" event", op);
460 
461  if (options & cib_xpath) {
462  return cib_process_xpath(op, options, section, req, input,
463  existing_cib, result_cib, answer);
464  }
465 
466  if (input == NULL) {
467  crm_err("Cannot perform modification with no data");
468  return -EINVAL;
469  }
470 
471  obj_root = pcmk_find_cib_element(*result_cib, section);
472  if (obj_root == NULL) {
473  xmlNode *tmp_section = NULL;
474  const char *path = pcmk_cib_parent_name_for(section);
475 
476  if (path == NULL) {
477  return -EINVAL;
478  }
479 
480  tmp_section = pcmk__xe_create(NULL, section);
481  cib_process_xpath(PCMK__CIB_REQUEST_CREATE, 0, path, NULL, tmp_section,
482  NULL, result_cib, answer);
483  pcmk__xml_free(tmp_section);
484 
485  obj_root = pcmk_find_cib_element(*result_cib, section);
486  }
487 
488  CRM_CHECK(obj_root != NULL, return -EINVAL);
489 
490  if (pcmk_is_set(options, cib_score_update)) {
492  }
493 
494  if (pcmk__xe_update_match(obj_root, input, flags) != pcmk_rc_ok) {
495  if (options & cib_can_create) {
496  pcmk__xml_copy(obj_root, input);
497  } else {
498  return -ENXIO;
499  }
500  }
501 
502  return pcmk_ok;
503 }
504 
505 static int
506 add_cib_object(xmlNode * parent, xmlNode * new_obj)
507 {
508  const char *object_name = NULL;
509  const char *object_id = NULL;
510 
511  if ((parent == NULL) || (new_obj == NULL)) {
512  return -EINVAL;
513  }
514 
515  object_name = (const char *) new_obj->name;
516  if (object_name == NULL) {
517  return -EINVAL;
518  }
519 
520  object_id = pcmk__xe_id(new_obj);
521  if (pcmk__xe_first_child(parent, object_name,
522  ((object_id != NULL)? PCMK_XA_ID : NULL),
523  object_id)) {
524  return -EEXIST;
525  }
526 
527  if (object_id != NULL) {
528  crm_trace("Processing creation of <%s " PCMK_XA_ID "='%s'>",
529  object_name, object_id);
530  } else {
531  crm_trace("Processing creation of <%s>", object_name);
532  }
533 
534  /* @COMPAT PCMK__XA_REPLACE is deprecated since 2.1.6. Due to a legacy use
535  * case, PCMK__XA_REPLACE has special meaning and should not be included in
536  * the newly created object until we can break behavioral backward
537  * compatibility.
538  *
539  * At a compatibility break, drop this and drop the definition of
540  * PCMK__XA_REPLACE. Treat it like any other attribute.
541  */
543  (void *) PCMK__XA_REPLACE);
544 
545  pcmk__xml_copy(parent, new_obj);
546  return pcmk_ok;
547 }
548 
549 static bool
550 update_results(xmlNode *failed, xmlNode *target, const char *operation,
551  int return_code)
552 {
553  xmlNode *xml_node = NULL;
554  bool was_error = false;
555  const char *error_msg = NULL;
556 
557  if (return_code != pcmk_ok) {
558  error_msg = pcmk_strerror(return_code);
559 
560  was_error = true;
561  xml_node = pcmk__xe_create(failed, PCMK__XE_FAILED_UPDATE);
562  pcmk__xml_copy(xml_node, target);
563 
564  crm_xml_add(xml_node, PCMK_XA_ID, pcmk__xe_id(target));
565  crm_xml_add(xml_node, PCMK_XA_OBJECT_TYPE, (const char *) target->name);
566  crm_xml_add(xml_node, PCMK_XA_OPERATION, operation);
567  crm_xml_add(xml_node, PCMK_XA_REASON, error_msg);
568 
569  crm_warn("Action %s failed: %s (cde=%d)",
570  operation, error_msg, return_code);
571  }
572 
573  return was_error;
574 }
575 
576 int
577 cib_process_create(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
578  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
579 {
580  xmlNode *failed = NULL;
581  int result = pcmk_ok;
582  xmlNode *update_section = NULL;
583 
584  crm_trace("Processing %s for %s section",
585  op, pcmk__s(section, "unspecified"));
586  if (pcmk__str_eq(PCMK__XE_ALL, section, pcmk__str_casei)) {
587  section = NULL;
588 
589  } else if (pcmk__str_eq(section, PCMK_XE_CIB, pcmk__str_casei)) {
590  section = NULL;
591 
592  } else if (pcmk__xe_is(input, PCMK_XE_CIB)) {
593  section = NULL;
594  }
595 
596  CRM_CHECK(strcmp(op, PCMK__CIB_REQUEST_CREATE) == 0, return -EINVAL);
597 
598  if (input == NULL) {
599  crm_err("Cannot perform modification with no data");
600  return -EINVAL;
601  }
602 
603  if (section == NULL) {
604  return cib_process_modify(op, options, section, req, input, existing_cib, result_cib,
605  answer);
606  }
607 
608  // @COMPAT Deprecated since 2.1.8
609  failed = pcmk__xe_create(NULL, PCMK__XE_FAILED);
610 
611  update_section = pcmk_find_cib_element(*result_cib, section);
612  if (pcmk__xe_is(input, section)) {
613  xmlNode *a_child = NULL;
614 
615  for (a_child = pcmk__xml_first_child(input); a_child != NULL;
616  a_child = pcmk__xml_next(a_child)) {
617  result = add_cib_object(update_section, a_child);
618  if (update_results(failed, a_child, op, result)) {
619  break;
620  }
621  }
622 
623  } else {
624  result = add_cib_object(update_section, input);
625  update_results(failed, input, op, result);
626  }
627 
628  if ((result == pcmk_ok) && (failed->children != NULL)) {
629  result = -EINVAL;
630  }
631 
632  if (result != pcmk_ok) {
633  crm_log_xml_err(failed, "CIB Update failures");
634  *answer = failed;
635 
636  } else {
637  pcmk__xml_free(failed);
638  }
639 
640  return result;
641 }
642 
643 int
644 cib_process_diff(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
645  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
646 {
647  const char *originator = NULL;
648 
649  if (req != NULL) {
650  originator = crm_element_value(req, PCMK__XA_SRC);
651  }
652 
653  crm_trace("Processing \"%s\" event from %s%s",
654  op, originator,
655  (pcmk_is_set(options, cib_force_diff)? " (global update)" : ""));
656 
657  if (*result_cib != existing_cib) {
658  pcmk__xml_free(*result_cib);
659  }
660  *result_cib = pcmk__xml_copy(NULL, existing_cib);
661 
662  return xml_apply_patchset(*result_cib, input, TRUE);
663 }
664 
665 int
666 cib_process_xpath(const char *op, int options, const char *section,
667  const xmlNode *req, xmlNode *input, xmlNode *existing_cib,
668  xmlNode **result_cib, xmlNode **answer)
669 {
670  int lpc = 0;
671  int max = 0;
672  int rc = pcmk_ok;
673  bool is_query = pcmk__str_eq(op, PCMK__CIB_REQUEST_QUERY, pcmk__str_none);
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)
688  && pcmk__str_eq(op, PCMK__CIB_REQUEST_DELETE, pcmk__str_none)) {
689  crm_debug("%s was already removed", section);
690 
691  } else if (max < 1) {
692  crm_debug("%s: %s does not exist", op, section);
693  rc = -ENXIO;
694 
695  } else if (is_query) {
696  if (max > 1) {
697  *answer = pcmk__xe_create(NULL, PCMK__XE_XPATH_QUERY);
698  }
699  }
700 
701  if (pcmk_is_set(options, cib_multiple)
702  && pcmk__str_eq(op, PCMK__CIB_REQUEST_DELETE, pcmk__str_none)) {
703  dedupXpathResults(xpathObj);
704  }
705 
706  for (lpc = 0; lpc < max; lpc++) {
707  xmlChar *path = NULL;
708  xmlNode *match = getXpathResult(xpathObj, lpc);
709 
710  if (match == NULL) {
711  continue;
712  }
713 
714  path = xmlGetNodePath(match);
715  crm_debug("Processing %s op for %s with %s", op, section, path);
716  free(path);
717 
718  if (pcmk__str_eq(op, PCMK__CIB_REQUEST_DELETE, pcmk__str_none)) {
719  if (match == *result_cib) {
720  /* Attempting to delete the whole "/cib" */
721  crm_warn("Cannot perform %s for %s: The xpath is addressing the whole /cib", op, section);
722  rc = -EINVAL;
723  break;
724  }
725 
726  pcmk__xml_free(match);
727  if ((options & cib_multiple) == 0) {
728  break;
729  }
730 
731  } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_MODIFY, pcmk__str_none)) {
732  uint32_t flags = pcmk__xaf_none;
733 
734  if (pcmk_is_set(options, cib_score_update)) {
736  }
737 
738  if (pcmk__xe_update_match(match, input, flags) != pcmk_rc_ok) {
739  rc = -ENXIO;
740  } else if ((options & cib_multiple) == 0) {
741  break;
742  }
743 
744  } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_CREATE, pcmk__str_none)) {
745  pcmk__xml_copy(match, input);
746  break;
747 
748  } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_QUERY, pcmk__str_none)) {
749 
750  if (options & cib_no_children) {
751  xmlNode *shallow = pcmk__xe_create(*answer,
752  (const char *) match->name);
753 
754  pcmk__xe_copy_attrs(shallow, match, pcmk__xaf_none);
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, PCMK_XA_ID);
766  char *new_path = NULL;
767 
768  if (id) {
769  new_path = crm_strdup_printf("/%s[@" PCMK_XA_ID "='%s']"
770  "%s",
771  parent->name, id,
772  pcmk__s(path, ""));
773  } else {
774  new_path = crm_strdup_printf("/%s%s", parent->name,
775  pcmk__s(path, ""));
776  }
777  free(path);
778  path = new_path;
779  parent = parent->parent;
780  }
781  crm_trace("Got: %s", path);
782 
783  if (*answer == NULL) {
784  *answer = pcmk__xe_create(NULL, PCMK__XE_XPATH_QUERY);
785  }
788  free(path);
789 
790  } else if (*answer) {
791  pcmk__xml_copy(*answer, match);
792 
793  } else {
794  *answer = match;
795  }
796 
797  } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_REPLACE,
798  pcmk__str_none)) {
799  xmlNode *parent = match->parent;
800 
801  pcmk__xml_free(match);
803 
804  if ((options & cib_multiple) == 0) {
805  break;
806  }
807  }
808  }
809 
810  freeXpathObject(xpathObj);
811  return rc;
812 }
#define pcmk_err_old_data
Definition: results.h:73
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:213
#define PCMK__XE_FAILED
#define PCMK__XA_DIGEST
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition: xml.c:805
A dumping ground.
int cib__get_operation(const char *op, const cib__operation_t **operation)
Definition: cib_ops.c:144
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition: xml_element.c:42
const char * pcmk_strerror(int rc)
Definition: results.c:257
gboolean cib_version_details(xmlNode *cib, int *admin_epoch, int *epoch, int *updates)
Definition: cib_utils.c:28
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:577
int pcmk__cmp_schemas_by_name(const char *schema1_name, const char *schema2_name)
Definition: schemas.c:662
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:453
int pcmk_rc2legacy(int rc)
Definition: results.c:654
#define PCMK__CIB_REQUEST_SYNC_TO_ONE
Definition: internal.h:27
#define PCMK__CIB_REQUEST_PRIMARY
Definition: internal.h:25
#define PCMK_XE_CIB
Definition: xml_names.h:79
#define PCMK__CIB_REQUEST_CREATE
Definition: internal.h:31
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:425
bool pcmk__xe_remove_attr_cb(xmlNode *xml, void *user_data)
Definition: xml_element.c:361
#define PCMK__CIB_REQUEST_QUERY
Definition: internal.h:30
#define PCMK_XA_NUM_UPDATES
Definition: xml_names.h:341
#define PCMK__XE_FAILED_UPDATE
#define PCMK__CIB_REQUEST_COMMIT_TRANSACT
Definition: internal.h:41
#define PCMK__XE_XPATH_QUERY
int pcmk__xe_foreach_child(xmlNode *xml, const char *child_element_name, int(*handler)(xmlNode *xml, void *userdata), void *userdata)
Definition: xml_element.c:979
int pcmk__xe_update_match(xmlNode *xml, xmlNode *update, uint32_t flags)
Definition: xml_element.c:926
Supported in a transaction.
Definition: internal.h:56
char * pcmk__digest_xml(xmlNode *input, bool filter)
Definition: digest.c:160
void dedupXpathResults(xmlXPathObjectPtr xpathObj)
Definition: xpath.c:101
#define PCMK__XA_CIB_SCHEMA_MAX
#define PCMK_XA_OPERATION
Definition: xml_names.h:349
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition: xml_element.c:407
int pcmk__xe_delete_match(xmlNode *xml, xmlNode *search)
Definition: xml_element.c:717
#define PCMK__CIB_REQUEST_ERASE
Definition: internal.h:34
void pcmk__xml_free(xmlNode *xml)
Definition: xml.c:789
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:644
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: xml_element.c:1015
#define PCMK__CIB_REQUEST_ABS_DELETE
Definition: internal.h:38
#define crm_warn(fmt, args...)
Definition: logging.h:362
Writes to disk on success.
Definition: internal.h:55
Modifies CIB.
Definition: internal.h:51
#define crm_debug(fmt, args...)
Definition: logging.h:370
int xml_apply_patchset(xmlNode *xml, xmlNode *patchset, bool check_version)
Definition: patchset.c:759
#define PCMK__CIB_REQUEST_IS_PRIMARY
Definition: internal.h:28
xmlNode * pcmk_find_cib_element(xmlNode *cib, const char *element_name)
Find an element in the CIB.
Definition: cib.c:172
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:260
#define PCMK_XA_REASON
Definition: xml_names.h:371
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition: xml_element.c:1466
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: xml_element.c:1168
#define crm_trace(fmt, args...)
Definition: logging.h:372
int cib_process_xpath(const char *op, int options, const char *section, const xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:666
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:80
#define PCMK_XA_EPOCH
Definition: xml_names.h:268
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:241
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:168
#define PCMK__NELEM(a)
Definition: internal.h:49
Flag has no effect.
Definition: xml_internal.h:362
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:150
#define PCMK__XE_ALL
#define PCMK_XA_ID
Definition: xml_names.h:301
Must only be processed locally.
Definition: internal.h:53
#define pcmk__str_copy(str)
#define PCMK_XA_VALIDATE_WITH
Definition: xml_names.h:441
#define PCMK__XE_XPATH_QUERY_PATH
int pcmk__update_schema(xmlNode **xml, const char *max_schema_name, bool transform, bool to_logs)
Update CIB XML to latest schema that validates it.
Definition: schemas.c:1047
#define PCMK__CIB_REQUEST_UPGRADE
Definition: internal.h:37
#define pcmk__assert(expr)
#define PCMK__CIB_REQUEST_BUMP
Definition: internal.h:29
const char * target
Definition: pcmk_fence.c:31
Replaces CIB.
Definition: internal.h:54
xmlNode * createEmptyCib(int cib_epoch)
Create XML for a new (empty) CIB.
Definition: cib_utils.c:118
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:304
Requires privileges.
Definition: internal.h:52
xmlXPathObjectPtr xpath_search(const xmlNode *xml_top, const char *path)
Definition: xpath.c:139
#define crm_log_xml_err(xml, text)
Definition: logging.h:375
int pcmk__xe_copy_attrs(xmlNode *target, const xmlNode *src, uint32_t flags)
Definition: xml_element.c:252
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:685
pcmk__action_result_t result
Definition: pcmk_fence.c:37
#define PCMK__CIB_REQUEST_SCHEMAS
Definition: internal.h:42
const char * path
Definition: cib.c:28
#define crm_err(fmt, args...)
Definition: logging.h:359
Prefer stderr to logs.
Definition: cib_types.h:57
#define PCMK__CIB_REQUEST_REPLACE
Definition: internal.h:35
xmlNode * input
xmlNode * getXpathResult(xmlXPathObjectPtr xpathObj, int index)
Definition: xpath.c:58
#define PCMK__CIB_REQUEST_SYNC_TO_ALL
Definition: internal.h:26
#define PCMK__CIB_REQUEST_SECONDARY
Definition: internal.h:24
#define PCMK__CIB_REQUEST_NOOP
Definition: internal.h:39
const char * name
Definition: internal.h:96
#define pcmk_ok
Definition: results.h:65
bool pcmk__xml_tree_foreach(xmlNode *xml, bool(*fn)(xmlNode *, void *), void *user_data)
Definition: xml.c:47
int pcmk__xe_replace_match(xmlNode *xml, xmlNode *replace)
Definition: xml_element.c:832
#define PCMK__CIB_REQUEST_MODIFY
Definition: internal.h:32
#define CRM_OP_PING
Definition: crm.h:112
const char * parent
Definition: cib.c:27
#define PCMK_XA_OBJECT_TYPE
Definition: xml_names.h:344
#define PCMK_XA_ADMIN_EPOCH
Definition: xml_names.h:232
void freeXpathObject(xmlXPathObjectPtr xpathObj)
Definition: xpath.c:39
Treat new attribute values as atomic score updates where possible.
Definition: cib_types.h:109
No special attributes.
Definition: internal.h:50
#define PCMK__CIB_REQUEST_SHUTDOWN
Definition: internal.h:40
#define crm_info(fmt, args...)
Definition: logging.h:367
#define PCMK__XA_REPLACE
#define PCMK__CIB_REQUEST_APPLY_PATCH
Definition: internal.h:36
#define PCMK__XA_SRC
uint64_t flags
Definition: remote.c:211
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:289
#define PCMK__CIB_REQUEST_DELETE
Definition: internal.h:33
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1