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