pacemaker 2.1.1-77db578727
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
cib_utils.c
Go to the documentation of this file.
1/*
2 * Original copyright 2004 International Business Machines
3 * Later changes copyright 2008-2021 the Pacemaker project contributors
4 *
5 * The version control history for this file may have further details.
6 *
7 * This source code is licensed under the GNU Lesser General Public License
8 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
9 */
10#include <crm_internal.h>
11#include <unistd.h>
12#include <stdlib.h>
13#include <stdio.h>
14#include <stdarg.h>
15#include <string.h>
16#include <sys/utsname.h>
17
18#include <glib.h>
19
20#include <crm/crm.h>
21#include <crm/cib/internal.h>
22#include <crm/msg_xml.h>
24#include <crm/common/xml.h>
26#include <crm/pengine/rules.h>
27
28struct config_root_s {
29 const char *name;
30 const char *parent;
31 const char *path;
32};
33
34 /*
35 * "//crm_config" will also work in place of "/cib/configuration/crm_config"
36 * The / prefix means find starting from the root, whereas the // prefix means
37 * find anywhere and risks multiple matches
38 */
39/* *INDENT-OFF* */
40static struct config_root_s known_paths[] = {
41 { NULL, NULL, "//cib" },
42 { XML_TAG_CIB, NULL, "//cib" },
43 { XML_CIB_TAG_STATUS, "/cib", "//cib/status" },
44 { XML_CIB_TAG_CONFIGURATION, "/cib", "//cib/configuration" },
45 { XML_CIB_TAG_CRMCONFIG, "/cib/configuration", "//cib/configuration/crm_config" },
46 { XML_CIB_TAG_NODES, "/cib/configuration", "//cib/configuration/nodes" },
47 { XML_CIB_TAG_RESOURCES, "/cib/configuration", "//cib/configuration/resources" },
48 { XML_CIB_TAG_CONSTRAINTS, "/cib/configuration", "//cib/configuration/constraints" },
49 { XML_CIB_TAG_OPCONFIG, "/cib/configuration", "//cib/configuration/op_defaults" },
50 { XML_CIB_TAG_RSCCONFIG, "/cib/configuration", "//cib/configuration/rsc_defaults" },
51 { XML_CIB_TAG_ACLS, "/cib/configuration", "//cib/configuration/acls" },
52 { XML_TAG_FENCING_TOPOLOGY, "/cib/configuration", "//cib/configuration/fencing-topology" },
53 { XML_CIB_TAG_TAGS, "/cib/configuration", "//cib/configuration/tags" },
54 { XML_CIB_TAG_ALERTS, "/cib/configuration", "//cib/configuration/alerts" },
55 { XML_CIB_TAG_SECTION_ALL, NULL, "//cib" },
56};
57/* *INDENT-ON* */
58
59xmlNode *
61{
62 xmlNode *the_cib = NULL;
63 xmlNode *generation = create_xml_node(NULL, XML_CIB_TAG_GENERATION_TUPPLE);
64
65 cib->cmds->query(cib, NULL, &the_cib, cib_scope_local | cib_sync_call);
66 if (the_cib != NULL) {
67 copy_in_properties(generation, the_cib);
68 free_xml(the_cib);
69 }
70
71 return generation;
72}
73
74gboolean
75cib_version_details(xmlNode * cib, int *admin_epoch, int *epoch, int *updates)
76{
77 *epoch = -1;
78 *updates = -1;
79 *admin_epoch = -1;
80
81 if (cib == NULL) {
82 return FALSE;
83
84 } else {
88 }
89 return TRUE;
90}
91
92gboolean
93cib_diff_version_details(xmlNode * diff, int *admin_epoch, int *epoch, int *updates,
94 int *_admin_epoch, int *_epoch, int *_updates)
95{
96 int add[] = { 0, 0, 0 };
97 int del[] = { 0, 0, 0 };
98
99 xml_patch_versions(diff, add, del);
100
101 *admin_epoch = add[0];
102 *epoch = add[1];
103 *updates = add[2];
104
105 *_admin_epoch = del[0];
106 *_epoch = del[1];
107 *_updates = del[2];
108
109 return TRUE;
110}
111
112/*
113 * The caller should never free the return value
114 */
115
116const char *
117get_object_path(const char *object_type)
118{
119 int lpc = 0;
120 int max = PCMK__NELEM(known_paths);
121
122 for (; lpc < max; lpc++) {
123 if ((object_type == NULL && known_paths[lpc].name == NULL)
124 || pcmk__str_eq(object_type, known_paths[lpc].name, pcmk__str_casei)) {
125 return known_paths[lpc].path;
126 }
127 }
128 return NULL;
129}
130
131const char *
132get_object_parent(const char *object_type)
133{
134 int lpc = 0;
135 int max = PCMK__NELEM(known_paths);
136
137 for (; lpc < max; lpc++) {
138 if (pcmk__str_eq(object_type, known_paths[lpc].name, pcmk__str_casei)) {
139 return known_paths[lpc].parent;
140 }
141 }
142 return NULL;
143}
144
145xmlNode *
146get_object_root(const char *object_type, xmlNode * the_root)
147{
148 const char *xpath = get_object_path(object_type);
149
150 if (xpath == NULL) {
151 return the_root; /* or return NULL? */
152 }
153
154 return get_xpath_object(xpath, the_root, LOG_TRACE);
155}
156
165xmlNode *
166createEmptyCib(int cib_epoch)
167{
168 xmlNode *cib_root = NULL, *config = NULL;
169
170 cib_root = create_xml_node(NULL, XML_TAG_CIB);
173
174 crm_xml_add_int(cib_root, XML_ATTR_GENERATION, cib_epoch);
177
178 config = create_xml_node(cib_root, XML_CIB_TAG_CONFIGURATION);
180
185
186#if PCMK__RESOURCE_STICKINESS_DEFAULT != 0
187 {
188 xmlNode *rsc_defaults = create_xml_node(config, XML_CIB_TAG_RSCCONFIG);
189 xmlNode *meta = create_xml_node(rsc_defaults, XML_TAG_META_SETS);
190 xmlNode *nvpair = create_xml_node(meta, XML_CIB_TAG_NVPAIR);
191
192 crm_xml_add(meta, XML_ATTR_ID, "build-resource-defaults");
197 }
198#endif
199 return cib_root;
200}
201
202static bool
203cib_acl_enabled(xmlNode *xml, const char *user)
204{
205 bool rc = FALSE;
206
207 if(pcmk_acl_required(user)) {
208 const char *value = NULL;
209 GHashTable *options = pcmk__strkey_table(free, free);
210
211 cib_read_config(options, xml);
212 value = cib_pref(options, "enable-acl");
213 rc = crm_is_true(value);
214 g_hash_table_destroy(options);
215 }
216
217 crm_trace("CIB ACL is %s", rc ? "enabled" : "disabled");
218 return rc;
219}
220
221int
222cib_perform_op(const char *op, int call_options, cib_op_t * fn, gboolean is_query,
223 const char *section, xmlNode * req, xmlNode * input,
224 gboolean manage_counters, gboolean * config_changed,
225 xmlNode * current_cib, xmlNode ** result_cib, xmlNode ** diff, xmlNode ** output)
226{
227 int rc = pcmk_ok;
228 gboolean check_schema = TRUE;
229 xmlNode *top = NULL;
230 xmlNode *scratch = NULL;
231 xmlNode *local_diff = NULL;
232
233 const char *new_version = NULL;
234 static struct qb_log_callsite *diff_cs = NULL;
235 const char *user = crm_element_value(req, F_CIB_USER);
236 bool with_digest = FALSE;
237
238 crm_trace("Begin %s%s%s op",
239 (pcmk_is_set(call_options, cib_dryrun)? "dry run of " : ""),
240 (is_query? "read-only " : ""), op);
241
242 CRM_CHECK(output != NULL, return -ENOMSG);
243 CRM_CHECK(result_cib != NULL, return -ENOMSG);
244 CRM_CHECK(config_changed != NULL, return -ENOMSG);
245
246 if(output) {
247 *output = NULL;
248 }
249
250 *result_cib = NULL;
251 *config_changed = FALSE;
252
253 if (fn == NULL) {
254 return -EINVAL;
255 }
256
257 if (is_query) {
258 xmlNode *cib_ro = current_cib;
259 xmlNode *cib_filtered = NULL;
260
261 if(cib_acl_enabled(cib_ro, user)) {
262 if(xml_acl_filtered_copy(user, current_cib, current_cib, &cib_filtered)) {
263 if (cib_filtered == NULL) {
264 crm_debug("Pre-filtered the entire cib");
265 return -EACCES;
266 }
267 cib_ro = cib_filtered;
268 crm_log_xml_trace(cib_ro, "filtered");
269 }
270 }
271
272 rc = (*fn) (op, call_options, section, req, input, cib_ro, result_cib, output);
273
274 if(output == NULL || *output == NULL) {
275 /* nothing */
276
277 } else if(cib_filtered == *output) {
278 cib_filtered = NULL; /* Let them have this copy */
279
280 } else if(*output == current_cib) {
281 /* They already know not to free it */
282
283 } else if(cib_filtered && (*output)->doc == cib_filtered->doc) {
284 /* We're about to free the document of which *output is a part */
285 *output = copy_xml(*output);
286
287 } else if((*output)->doc == current_cib->doc) {
288 /* Give them a copy they can free */
289 *output = copy_xml(*output);
290 }
291
292 free_xml(cib_filtered);
293 return rc;
294 }
295
296
297 if (pcmk_is_set(call_options, cib_zero_copy)) {
298 /* Conditional on v2 patch style */
299
300 scratch = current_cib;
301
302 /* Create a shallow copy of current_cib for the version details */
303 current_cib = create_xml_node(NULL, (const char *)scratch->name);
304 copy_in_properties(current_cib, scratch);
305 top = current_cib;
306
307 xml_track_changes(scratch, user, NULL, cib_acl_enabled(scratch, user));
308 rc = (*fn) (op, call_options, section, req, input, scratch, &scratch, output);
309
310 } else {
311 scratch = copy_xml(current_cib);
312 xml_track_changes(scratch, user, NULL, cib_acl_enabled(scratch, user));
313 rc = (*fn) (op, call_options, section, req, input, current_cib, &scratch, output);
314
315 if(scratch && xml_tracking_changes(scratch) == FALSE) {
316 crm_trace("Inferring changes after %s op", op);
317 xml_track_changes(scratch, user, current_cib, cib_acl_enabled(current_cib, user));
318 xml_calculate_changes(current_cib, scratch);
319 }
320 CRM_CHECK(current_cib != scratch, return -EINVAL);
321 }
322
323 xml_acl_disable(scratch); /* Allow the system to make any additional changes */
324
325 if (rc == pcmk_ok && scratch == NULL) {
326 rc = -EINVAL;
327 goto done;
328
329 } else if(rc == pcmk_ok && xml_acl_denied(scratch)) {
330 crm_trace("ACL rejected part or all of the proposed changes");
331 rc = -EACCES;
332 goto done;
333
334 } else if (rc != pcmk_ok) {
335 goto done;
336 }
337
338 if (scratch) {
339 new_version = crm_element_value(scratch, XML_ATTR_CRM_VERSION);
340
341 if (new_version && compare_version(new_version, CRM_FEATURE_SET) > 0) {
342 crm_err("Discarding update with feature set '%s' greater than our own '%s'",
343 new_version, CRM_FEATURE_SET);
344 rc = -EPROTONOSUPPORT;
345 goto done;
346 }
347 }
348
349 if (current_cib) {
350 int old = 0;
351 int new = 0;
352
355
356 if (old > new) {
357 crm_err("%s went backwards: %d -> %d (Opts: 0x%x)",
358 XML_ATTR_GENERATION_ADMIN, old, new, call_options);
359 crm_log_xml_warn(req, "Bad Op");
360 crm_log_xml_warn(input, "Bad Data");
362
363 } else if (old == new) {
365 crm_element_value_int(current_cib, XML_ATTR_GENERATION, &old);
366 if (old > new) {
367 crm_err("%s went backwards: %d -> %d (Opts: 0x%x)",
368 XML_ATTR_GENERATION, old, new, call_options);
369 crm_log_xml_warn(req, "Bad Op");
370 crm_log_xml_warn(input, "Bad Data");
372 }
373 }
374 }
375
376 crm_trace("Massaging CIB contents");
377 pcmk__strip_xml_text(scratch);
379
380 if (pcmk_is_set(call_options, cib_zero_copy)) {
381 /* At this point, current_cib is just the 'cib' tag and its properties,
382 *
383 * The v1 format would barf on this, but we know the v2 patch
384 * format only needs it for the top-level version fields
385 */
386 local_diff = xml_create_patchset(2, current_cib, scratch, (bool*)config_changed, manage_counters);
387
388 } else {
389 static time_t expires = 0;
390 time_t tm_now = time(NULL);
391
392 if (expires < tm_now) {
393 expires = tm_now + 60; /* Validate clients are correctly applying v2-style diffs at most once a minute */
394 with_digest = TRUE;
395 }
396
397 local_diff = xml_create_patchset(0, current_cib, scratch, (bool*)config_changed, manage_counters);
398 }
399
400 xml_log_changes(LOG_TRACE, __func__, scratch);
401 xml_accept_changes(scratch);
402
403 if (diff_cs == NULL) {
404 diff_cs = qb_log_callsite_get(__PRETTY_FUNCTION__, __FILE__, "diff-validation", LOG_DEBUG, __LINE__, crm_trace_nonlog);
405 }
406
407 if(local_diff) {
408 patchset_process_digest(local_diff, current_cib, scratch, with_digest);
409
410 xml_log_patchset(LOG_INFO, __func__, local_diff);
411 crm_log_xml_trace(local_diff, "raw patch");
412 }
413
414 if (!pcmk_is_set(call_options, cib_zero_copy) // Original to compare against doesn't exist
415 && local_diff
416 && crm_is_callsite_active(diff_cs, LOG_TRACE, 0)) {
417
418 /* Validate the calculated patch set */
419 int test_rc, format = 1;
420 xmlNode * c = copy_xml(current_cib);
421
422 crm_element_value_int(local_diff, "format", &format);
423 test_rc = xml_apply_patchset(c, local_diff, manage_counters);
424
425 if(test_rc != pcmk_ok) {
426 save_xml_to_file(c, "PatchApply:calculated", NULL);
427 save_xml_to_file(current_cib, "PatchApply:input", NULL);
428 save_xml_to_file(scratch, "PatchApply:actual", NULL);
429 save_xml_to_file(local_diff, "PatchApply:diff", NULL);
430 crm_err("v%d patchset error, patch failed to apply: %s (%d)", format, pcmk_strerror(test_rc), test_rc);
431 }
432 free_xml(c);
433 }
434
435 if (pcmk__str_eq(section, XML_CIB_TAG_STATUS, pcmk__str_casei)) {
436 /* Throttle the amount of costly validation we perform due to status updates
437 * a) we don't really care whats in the status section
438 * b) we don't validate any of its contents at the moment anyway
439 */
440 check_schema = FALSE;
441 }
442
443 /* === scratch must not be modified after this point ===
444 * Exceptions, anything in:
445
446 static filter_t filter[] = {
447 { 0, XML_ATTR_ORIGIN },
448 { 0, XML_CIB_ATTR_WRITTEN },
449 { 0, XML_ATTR_UPDATE_ORIG },
450 { 0, XML_ATTR_UPDATE_CLIENT },
451 { 0, XML_ATTR_UPDATE_USER },
452 };
453 */
454
455 if (*config_changed && !pcmk_is_set(call_options, cib_no_mtime)) {
456 const char *schema = crm_element_value(scratch, XML_ATTR_VALIDATION);
457
459 if (schema) {
460 static int minimum_schema = 0;
461 int current_schema = get_schema_version(schema);
462
463 if (minimum_schema == 0) {
464 minimum_schema = get_schema_version("pacemaker-1.2");
465 }
466
467 /* Does the CIB support the "update-*" attributes... */
468 if (current_schema >= minimum_schema) {
469 const char *origin = crm_element_value(req, F_ORIG);
470
471 CRM_LOG_ASSERT(origin != NULL);
472 crm_xml_replace(scratch, XML_ATTR_UPDATE_ORIG, origin);
476 }
477 }
478 }
479
480 crm_trace("Perform validation: %s", pcmk__btoa(check_schema));
481 if ((rc == pcmk_ok) && check_schema && !validate_xml(scratch, NULL, TRUE)) {
482 const char *current_schema = crm_element_value(scratch,
484
485 crm_warn("Updated CIB does not validate against %s schema",
486 crm_str(current_schema));
488 }
489
490 done:
491
492 *result_cib = scratch;
493 if(rc != pcmk_ok && cib_acl_enabled(current_cib, user)) {
494 if(xml_acl_filtered_copy(user, current_cib, scratch, result_cib)) {
495 if (*result_cib == NULL) {
496 crm_debug("Pre-filtered the entire cib result");
497 }
498 free_xml(scratch);
499 }
500 }
501
502 if(diff) {
503 *diff = local_diff;
504 } else {
505 free_xml(local_diff);
506 }
507
508 free_xml(top);
509 crm_trace("Done");
510 return rc;
511}
512
513xmlNode *
514cib_create_op(int call_id, const char *token, const char *op, const char *host, const char *section,
515 xmlNode * data, int call_options, const char *user_name)
516{
517 xmlNode *op_msg = create_xml_node(NULL, "cib_command");
518
519 CRM_CHECK(op_msg != NULL, return NULL);
520 CRM_CHECK(token != NULL, return NULL);
521
522 crm_xml_add(op_msg, F_XML_TAGNAME, "cib_command");
523
524 crm_xml_add(op_msg, F_TYPE, T_CIB);
525 crm_xml_add(op_msg, F_CIB_CALLBACK_TOKEN, token);
526 crm_xml_add(op_msg, F_CIB_OPERATION, op);
527 crm_xml_add(op_msg, F_CIB_HOST, host);
528 crm_xml_add(op_msg, F_CIB_SECTION, section);
529 crm_xml_add_int(op_msg, F_CIB_CALLID, call_id);
530 if (user_name) {
531 crm_xml_add(op_msg, F_CIB_USER, user_name);
532 }
533 crm_trace("Sending call options: %.8lx, %d", (long)call_options, call_options);
534 crm_xml_add_int(op_msg, F_CIB_CALLOPTS, call_options);
535
536 if (data != NULL) {
538 }
539
540 if (call_options & cib_inhibit_bcast) {
541 CRM_CHECK((call_options & cib_scope_local), return NULL);
542 }
543 return op_msg;
544}
545
546void
547cib_native_callback(cib_t * cib, xmlNode * msg, int call_id, int rc)
548{
549 xmlNode *output = NULL;
550 cib_callback_client_t *blob = NULL;
551
552 if (msg != NULL) {
554 crm_element_value_int(msg, F_CIB_CALLID, &call_id);
555 output = get_message_xml(msg, F_CIB_CALLDATA);
556 }
557
558 blob = pcmk__intkey_table_lookup(cib_op_callback_table, call_id);
559 if (blob == NULL) {
560 crm_trace("No callback found for call %d", call_id);
561 }
562
563 if (cib == NULL) {
564 crm_debug("No cib object supplied");
565 }
566
567 if (rc == -pcmk_err_diff_resync) {
568 /* This is an internal value that clients do not and should not care about */
569 rc = pcmk_ok;
570 }
571
572 if (blob && blob->callback && (rc == pcmk_ok || blob->only_success == FALSE)) {
573 crm_trace("Invoking callback %s for call %d", crm_str(blob->id), call_id);
574 blob->callback(msg, call_id, rc, output, blob->user_data);
575
576 } else if (cib && cib->op_callback == NULL && rc != pcmk_ok) {
577 crm_warn("CIB command failed: %s", pcmk_strerror(rc));
578 crm_log_xml_debug(msg, "Failed CIB Update");
579 }
580
581 /* This may free user_data, so do it after the callback */
582 if (blob) {
583 remove_cib_op_callback(call_id, FALSE);
584 }
585
586 if (cib && cib->op_callback != NULL) {
587 crm_trace("Invoking global callback for call %d", call_id);
588 cib->op_callback(msg, call_id, rc, output);
589 }
590 crm_trace("OP callback activated for %d", call_id);
591}
592
593void
594cib_native_notify(gpointer data, gpointer user_data)
595{
596 xmlNode *msg = user_data;
597 cib_notify_client_t *entry = data;
598 const char *event = NULL;
599
600 if (msg == NULL) {
601 crm_warn("Skipping callback - NULL message");
602 return;
603 }
604
605 event = crm_element_value(msg, F_SUBTYPE);
606
607 if (entry == NULL) {
608 crm_warn("Skipping callback - NULL callback client");
609 return;
610
611 } else if (entry->callback == NULL) {
612 crm_warn("Skipping callback - NULL callback");
613 return;
614
615 } else if (!pcmk__str_eq(entry->event, event, pcmk__str_casei)) {
616 crm_trace("Skipping callback - event mismatch %p/%s vs. %s", entry, entry->event, event);
617 return;
618 }
619
620 crm_trace("Invoking callback for %p/%s event...", entry, event);
621 entry->callback(event, msg);
622 crm_trace("Callback invoked...");
623}
624
625static pcmk__cluster_option_t cib_opts[] = {
626 /* name, legacy name, type, allowed values,
627 * default value, validator,
628 * short description,
629 * long description
630 */
631 {
632 "enable-acl", NULL, "boolean", NULL,
633 "false", pcmk__valid_boolean,
634 "Enable Access Control Lists (ACLs) for the CIB",
635 NULL
636 },
637 {
638 "cluster-ipc-limit", NULL, "integer", NULL,
640 "Maximum IPC message backlog before disconnecting a cluster daemon",
641 "Raise this if log has \"Evicting client\" messages for cluster daemon"
642 " PIDs (a good value is the number of resources in the cluster"
643 " multiplied by the number of nodes)."
644 },
645};
646
647void
649{
650 pcmk__print_option_metadata("pacemaker-based", "1.0",
651 "Cluster Information Base manager options",
652 "Cluster options used by Pacemaker's "
653 "Cluster Information Base manager",
654 cib_opts, PCMK__NELEM(cib_opts));
655}
656
657void
658verify_cib_options(GHashTable * options)
659{
660 pcmk__validate_cluster_options(options, cib_opts, PCMK__NELEM(cib_opts));
661}
662
663const char *
664cib_pref(GHashTable * options, const char *name)
665{
666 return pcmk__cluster_option(options, cib_opts, PCMK__NELEM(cib_opts),
667 name);
668}
669
670gboolean
671cib_read_config(GHashTable * options, xmlNode * current_cib)
672{
673 xmlNode *config = NULL;
674 crm_time_t *now = NULL;
675
676 if (options == NULL || current_cib == NULL) {
677 return FALSE;
678 }
679
680 now = crm_time_new(NULL);
681
682 g_hash_table_remove_all(options);
683
684 config = get_object_root(XML_CIB_TAG_CRMCONFIG, current_cib);
685 if (config) {
686 pe_unpack_nvpairs(current_cib, config, XML_CIB_TAG_PROPSET, NULL,
687 options, CIB_OPTIONS_FIRST, TRUE, now, NULL);
688 }
689
690 verify_cib_options(options);
691
692 crm_time_free(now);
693
694 return TRUE;
695}
696
697/* v2 and v2 patch formats */
698#define XPATH_CONFIG_CHANGE \
699 "//" XML_CIB_TAG_CRMCONFIG " | " \
700 "//" XML_DIFF_CHANGE "[contains(@" XML_DIFF_PATH ",'/" XML_CIB_TAG_CRMCONFIG "/')]"
701
702gboolean
704{
705 gboolean changed = FALSE;
706
707 if (diff) {
708 xmlXPathObject *xpathObj = xpath_search(diff, XPATH_CONFIG_CHANGE);
709
710 if (numXpathResults(xpathObj) > 0) {
711 changed = TRUE;
712 }
713 freeXpathObject(xpathObj);
714 }
715 return changed;
716}
717
718int
719cib_internal_op(cib_t * cib, const char *op, const char *host,
720 const char *section, xmlNode * data,
721 xmlNode ** output_data, int call_options, const char *user_name)
722{
723 int (*delegate) (cib_t * cib, const char *op, const char *host,
724 const char *section, xmlNode * data,
725 xmlNode ** output_data, int call_options, const char *user_name) =
726 cib->delegate_fn;
727
728 if(user_name == NULL) {
729 user_name = getenv("CIB_user");
730 }
731
732 return delegate(cib, op, host, section, data, output_data, call_options, user_name);
733}
734
746int
747cib_apply_patch_event(xmlNode *event, xmlNode *input, xmlNode **output,
748 int level)
749{
750 int rc = pcmk_err_generic;
751
752 xmlNode *diff = NULL;
753
754 CRM_ASSERT(event);
755 CRM_ASSERT(input);
756 CRM_ASSERT(output);
757
760
761 if (rc < pcmk_ok || diff == NULL) {
762 return rc;
763 }
764
765 if (level > LOG_CRIT) {
766 xml_log_patchset(level, "Config update", diff);
767 }
768
769 if (input != NULL) {
770 rc = cib_process_diff(NULL, cib_none, NULL, event, diff, input, output,
771 NULL);
772
773 if (rc != pcmk_ok) {
774 crm_debug("Update didn't apply: %s (%d) %p",
775 pcmk_strerror(rc), rc, *output);
776
777 if (rc == -pcmk_err_old_data) {
778 crm_trace("Masking error, we already have the supplied update");
779 return pcmk_ok;
780 }
781 free_xml(*output);
782 *output = NULL;
783 return rc;
784 }
785 }
786 return rc;
787}
bool pcmk_acl_required(const char *user)
Check whether ACLs are required for a given user.
Definition acl.c:671
bool xml_acl_denied(xmlNode *xml)
Definition acl.c:564
void xml_acl_disable(xmlNode *xml)
Definition acl.c:575
bool xml_acl_filtered_copy(const char *user, xmlNode *acl_source, xmlNode *xml, xmlNode **result)
Definition acl.c:403
#define F_CIB_CALLID
Definition internal.h:35
#define F_CIB_CALLOPTS
Definition internal.h:34
#define F_CIB_USER
Definition internal.h:57
#define F_CIB_OPERATION
Definition internal.h:37
#define T_CIB
Definition internal.h:62
#define F_CIB_HOST
Definition internal.h:40
#define F_CIB_RC
Definition internal.h:41
#define F_CIB_CLIENTNAME
Definition internal.h:53
GHashTable * cib_op_callback_table
Definition cib_client.c:28
#define F_CIB_SECTION
Definition internal.h:39
#define F_CIB_CALLDATA
Definition internal.h:36
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
#define F_CIB_UPDATE_RESULT
Definition internal.h:52
int(* cib_op_t)(const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **)
Definition internal.h:114
#define F_CIB_CALLBACK_TOKEN
Definition internal.h:50
void remove_cib_op_callback(int call_id, gboolean all_callbacks)
Definition cib_client.c:657
@ cib_scope_local
Definition cib_types.h:59
@ cib_none
Definition cib_types.h:50
@ cib_sync_call
Definition cib_types.h:61
@ cib_dryrun
Definition cib_types.h:60
@ cib_no_mtime
Definition cib_types.h:62
@ cib_zero_copy
Definition cib_types.h:63
@ cib_inhibit_bcast
Definition cib_types.h:66
int cib_apply_patch_event(xmlNode *event, xmlNode *input, xmlNode **output, int level)
Apply a CIB update patch to a given CIB.
Definition cib_utils.c:747
void cib_native_callback(cib_t *cib, xmlNode *msg, int call_id, int rc)
Definition cib_utils.c:547
void verify_cib_options(GHashTable *options)
Definition cib_utils.c:658
#define XPATH_CONFIG_CHANGE
Definition cib_utils.c:698
const char * cib_pref(GHashTable *options, const char *name)
Definition cib_utils.c:664
int cib_internal_op(cib_t *cib, const char *op, const char *host, const char *section, xmlNode *data, xmlNode **output_data, int call_options, const char *user_name)
Definition cib_utils.c:719
gboolean cib_diff_version_details(xmlNode *diff, int *admin_epoch, int *epoch, int *updates, int *_admin_epoch, int *_epoch, int *_updates)
Definition cib_utils.c:93
const char * get_object_path(const char *object_type)
Definition cib_utils.c:117
gboolean cib_version_details(xmlNode *cib, int *admin_epoch, int *epoch, int *updates)
Definition cib_utils.c:75
xmlNode * cib_get_generation(cib_t *cib)
Definition cib_utils.c:60
int cib_perform_op(const char *op, int call_options, cib_op_t *fn, gboolean is_query, const char *section, xmlNode *req, xmlNode *input, gboolean manage_counters, gboolean *config_changed, xmlNode *current_cib, xmlNode **result_cib, xmlNode **diff, xmlNode **output)
Definition cib_utils.c:222
const char * get_object_parent(const char *object_type)
Definition cib_utils.c:132
xmlNode * cib_create_op(int call_id, const char *token, const char *op, const char *host, const char *section, xmlNode *data, int call_options, const char *user_name)
Definition cib_utils.c:514
xmlNode * createEmptyCib(int cib_epoch)
Create XML for a new (empty) CIB.
Definition cib_utils.c:166
gboolean cib_internal_config_changed(xmlNode *diff)
Definition cib_utils.c:703
gboolean cib_read_config(GHashTable *options, xmlNode *current_cib)
Definition cib_utils.c:671
xmlNode * get_object_root(const char *object_type, xmlNode *the_root)
Definition cib_utils.c:146
void cib_metadata(void)
Definition cib_utils.c:648
void cib_native_notify(gpointer data, gpointer user_data)
Definition cib_utils.c:594
#define PCMK__NELEM(a)
Definition internal.h:38
int compare_version(const char *version1, const char *version2)
Definition utils.c:232
gboolean crm_is_true(const char *s)
Definition strings.c:415
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:114
#define PCMK__RESOURCE_STICKINESS_DEFAULT
Definition config.h:516
pcmk__cpg_host_t host
Definition cpg.c:4
char data[0]
Definition cpg.c:10
A dumping ground.
#define CRM_FEATURE_SET
Definition crm.h:69
void crm_time_free(crm_time_t *dt)
Definition iso8601.c:141
crm_time_t * crm_time_new(const char *string)
Definition iso8601.c:93
struct crm_time_s crm_time_t
Definition iso8601.h:32
gboolean crm_is_callsite_active(struct qb_log_callsite *cs, uint8_t level, uint32_t tags)
Definition logging.c:629
#define crm_str(x)
Definition logging.h:376
#define crm_warn(fmt, args...)
Definition logging.h:351
#define crm_log_xml_debug(xml, text)
Definition logging.h:363
#define CRM_LOG_ASSERT(expr)
Definition logging.h:202
unsigned int crm_trace_nonlog
Definition logging.c:46
#define CRM_CHECK(expr, failure_action)
Definition logging.h:218
#define crm_debug(fmt, args...)
Definition logging.h:355
#define crm_err(fmt, args...)
Definition logging.h:350
#define crm_log_xml_trace(xml, text)
Definition logging.h:364
#define crm_log_xml_warn(xml, text)
Definition logging.h:360
#define crm_trace(fmt, args...)
Definition logging.h:356
#define LOG_TRACE
Definition logging.h:36
#define F_SUBTYPE
Definition msg_xml.h:59
#define XML_CIB_TAG_GENERATION_TUPPLE
Definition msg_xml.h:396
#define XML_TAG_CIB
Definition msg_xml.h:109
#define XML_CIB_TAG_RESOURCES
Definition msg_xml.h:180
#define XML_CIB_TAG_TAGS
Definition msg_xml.h:429
#define XML_ATTR_CRM_VERSION
Definition msg_xml.h:112
#define XML_CIB_TAG_ACLS
Definition msg_xml.h:187
#define XML_NVPAIR_ATTR_VALUE
Definition msg_xml.h:378
#define XML_CIB_TAG_RSCCONFIG
Definition msg_xml.h:186
#define XML_CIB_TAG_ALERTS
Definition msg_xml.h:188
#define F_XML_TAGNAME
Definition msg_xml.h:71
#define XML_CIB_TAG_CRMCONFIG
Definition msg_xml.h:184
#define XML_CIB_TAG_SECTION_ALL
Definition msg_xml.h:177
#define XML_RSC_ATTR_STICKINESS
Definition msg_xml.h:236
#define XML_ATTR_ID
Definition msg_xml.h:129
#define XML_CIB_TAG_CONSTRAINTS
Definition msg_xml.h:183
#define F_ORIG
Definition msg_xml.h:51
#define XML_TAG_META_SETS
Definition msg_xml.h:204
#define XML_ATTR_UPDATE_CLIENT
Definition msg_xml.h:137
#define XML_CIB_TAG_CONFIGURATION
Definition msg_xml.h:178
#define XML_TAG_FENCING_TOPOLOGY
Definition msg_xml.h:433
#define F_TYPE
Definition msg_xml.h:63
#define XML_CIB_TAG_PROPSET
Definition msg_xml.h:202
#define XML_ATTR_VALIDATION
Definition msg_xml.h:114
#define XML_NVPAIR_ATTR_NAME
Definition msg_xml.h:377
#define XML_ATTR_GENERATION_ADMIN
Definition msg_xml.h:121
#define XML_ATTR_NUMUPDATES
Definition msg_xml.h:122
#define CIB_OPTIONS_FIRST
Definition msg_xml.h:82
#define XML_CIB_TAG_NODES
Definition msg_xml.h:181
#define XML_CIB_TAG_NVPAIR
Definition msg_xml.h:200
#define XML_CIB_TAG_STATUS
Definition msg_xml.h:179
#define XML_ATTR_UPDATE_ORIG
Definition msg_xml.h:136
#define XML_ATTR_UPDATE_USER
Definition msg_xml.h:138
#define XML_ATTR_GENERATION
Definition msg_xml.h:120
#define XML_CIB_TAG_OPCONFIG
Definition msg_xml.h:185
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:530
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition nvpair.c:566
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
Definition nvpair.c:432
const char * crm_xml_replace(xmlNode *node, const char *name, const char *value)
Replace an XML attribute with specified name and (possibly NULL) value.
Definition nvpair.c:381
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:324
bool pcmk__valid_boolean(const char *value)
Definition options.c:375
void pcmk__print_option_metadata(const char *name, const char *version, const char *desc_short, const char *desc_long, pcmk__cluster_option_t *option_list, int len)
Definition options.c:556
const char * pcmk__cluster_option(GHashTable *options, pcmk__cluster_option_t *option_list, int len, const char *name)
Definition options.c:537
void pcmk__validate_cluster_options(GHashTable *options, pcmk__cluster_option_t *option_list, int len)
Definition options.c:594
bool pcmk__valid_positive_number(const char *value)
Definition options.c:397
char * name
Definition pcmk_fence.c:31
int rc
Definition pcmk_fence.c:35
const char * pcmk_strerror(int rc)
Definition results.c:58
#define pcmk_err_old_data
Definition results.h:74
#define pcmk_err_generic
Definition results.h:70
#define CRM_ASSERT(expr)
Definition results.h:42
#define pcmk_err_schema_validation
Definition results.h:72
#define pcmk_ok
Definition results.h:67
#define pcmk_err_diff_resync
Definition results.h:76
void pe_unpack_nvpairs(xmlNode *top, xmlNode *xml_obj, const char *set_name, GHashTable *node_hash, GHashTable *hash, const char *always_first, gboolean overwrite, crm_time_t *now, crm_time_t *next_change)
Extract nvpair blocks contained by an XML element into a hash table.
Definition rules.c:628
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition strings.c:610
@ pcmk__str_casei
int(* query)(cib_t *cib, const char *section, xmlNode **output_data, int call_options)
Definition cib_types.h:92
const char * id
Definition internal.h:88
void(* callback)(xmlNode *, int, int, xmlNode *, void *)
Definition internal.h:87
gboolean only_success
Definition internal.h:90
const char * event
Definition internal.h:79
void(* callback)(const char *event, xmlNode *msg)
Definition internal.h:82
void * delegate_fn
Definition cib_types.h:142
cib_api_operations_t * cmds
Definition cib_types.h:147
void(* op_callback)(const xmlNode *msg, int call_id, int rc, xmlNode *output)
Definition cib_types.h:145
Wrappers for and extensions to libxml2.
void xml_log_changes(uint8_t level, const char *function, xmlNode *xml)
Definition xml.c:386
int get_schema_version(const char *name)
Definition schemas.c:1030
xmlXPathObjectPtr xpath_search(xmlNode *xml_top, const char *path)
Definition xpath.c:139
void fix_plus_plus_recursive(xmlNode *target)
Definition xml.c:542
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition xpath.c:214
void xml_accept_changes(xmlNode *xml)
Definition xml.c:421
void patchset_process_digest(xmlNode *patch, xmlNode *source, xmlNode *target, bool with_digest)
Definition patchset.c:427
bool xml_patch_versions(xmlNode *patchset, int add[3], int del[3])
Definition patchset.c:802
const char * xml_latest_schema(void)
Definition schemas.c:115
int xml_apply_patchset(xmlNode *xml, xmlNode *patchset, bool check_version)
Definition patchset.c:1326
void xml_calculate_changes(xmlNode *old_xml, xmlNode *new_xml)
Definition xml.c:2374
void freeXpathObject(xmlXPathObjectPtr xpathObj)
Definition xpath.c:39
gboolean add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
Definition messages.c:162
bool xml_tracking_changes(xmlNode *xml)
Definition xml.c:291
void xml_track_changes(xmlNode *xml, const char *user, xmlNode *acl_source, bool enforce_acls)
Definition xml.c:276
void free_xml(xmlNode *child)
Definition xml.c:823
void copy_in_properties(xmlNode *target, xmlNode *src)
Definition xml.c:521
gboolean validate_xml(xmlNode *xml_blob, const char *validation, gboolean to_logs)
Definition schemas.c:700
xmlNode * get_message_xml(xmlNode *msg, const char *field)
Definition messages.c:154
xmlNode * xml_create_patchset(int format, xmlNode *source, xmlNode *target, bool *config, bool manage_version)
Definition patchset.c:370
xmlNode * copy_xml(xmlNode *src_node)
Definition xml.c:829
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition xml.c:696
void xml_log_patchset(uint8_t level, const char *function, xmlNode *xml)
Definition patchset.c:458
void save_xml_to_file(xmlNode *xml, const char *desc, const char *filename)
Definition xml.c:2055
const char * pcmk__xe_add_last_written(xmlNode *xe)
Definition xml.c:1113
void pcmk__strip_xml_text(xmlNode *xml)
Definition xml.c:1015