This source file includes following definitions.
- cib_get_generation
- cib_version_details
- cib_diff_version_details
- get_object_path
- get_object_parent
- get_object_root
- createEmptyCib
- cib_acl_enabled
- cib_perform_op
- cib_create_op
- cib_native_callback
- cib_native_notify
- cib_metadata
- verify_cib_options
- cib_pref
- cib_read_config
- cib_internal_config_changed
- cib_internal_op
- cib_apply_patch_event
1
2
3
4
5
6
7
8
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>
23 #include <crm/common/iso8601_internal.h>
24 #include <crm/common/xml.h>
25 #include <crm/common/xml_internal.h>
26 #include <crm/pengine/rules.h>
27
28 struct config_root_s {
29 const char *name;
30 const char *parent;
31 const char *path;
32 };
33
34
35
36
37
38
39
40 static 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
58
59 xmlNode *
60 cib_get_generation(cib_t * cib)
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
74 gboolean
75 cib_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 {
85 crm_element_value_int(cib, XML_ATTR_GENERATION, epoch);
86 crm_element_value_int(cib, XML_ATTR_NUMUPDATES, updates);
87 crm_element_value_int(cib, XML_ATTR_GENERATION_ADMIN, admin_epoch);
88 }
89 return TRUE;
90 }
91
92 gboolean
93 cib_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
114
115
116 const char *
117 get_object_path(const char *object_type)
118 {
119 int lpc = 0;
120 int max = DIMOF(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
131 const char *
132 get_object_parent(const char *object_type)
133 {
134 int lpc = 0;
135 int max = DIMOF(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
145 xmlNode *
146 get_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;
152 }
153
154 return get_xpath_object(xpath, the_root, LOG_TRACE);
155 }
156
157
158
159
160
161 xmlNode *
162 createEmptyCib(int admin_epoch)
163 {
164 xmlNode *cib_root = NULL, *config = NULL;
165
166 cib_root = create_xml_node(NULL, XML_TAG_CIB);
167 crm_xml_add(cib_root, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
168 crm_xml_add(cib_root, XML_ATTR_VALIDATION, xml_latest_schema());
169
170 crm_xml_add_int(cib_root, XML_ATTR_GENERATION, admin_epoch);
171 crm_xml_add_int(cib_root, XML_ATTR_NUMUPDATES, 0);
172 crm_xml_add_int(cib_root, XML_ATTR_GENERATION_ADMIN, 0);
173
174 config = create_xml_node(cib_root, XML_CIB_TAG_CONFIGURATION);
175 create_xml_node(cib_root, XML_CIB_TAG_STATUS);
176
177 create_xml_node(config, XML_CIB_TAG_CRMCONFIG);
178 create_xml_node(config, XML_CIB_TAG_NODES);
179 create_xml_node(config, XML_CIB_TAG_RESOURCES);
180 create_xml_node(config, XML_CIB_TAG_CONSTRAINTS);
181
182 return cib_root;
183 }
184
185 static bool
186 cib_acl_enabled(xmlNode *xml, const char *user)
187 {
188 bool rc = FALSE;
189
190 #if ENABLE_ACL
191 if(pcmk_acl_required(user)) {
192 const char *value = NULL;
193 GHashTable *options = crm_str_table_new();
194
195 cib_read_config(options, xml);
196 value = cib_pref(options, "enable-acl");
197 rc = crm_is_true(value);
198 g_hash_table_destroy(options);
199 }
200
201 crm_trace("CIB ACL is %s", rc ? "enabled" : "disabled");
202 #endif
203 return rc;
204 }
205
206 int
207 cib_perform_op(const char *op, int call_options, cib_op_t * fn, gboolean is_query,
208 const char *section, xmlNode * req, xmlNode * input,
209 gboolean manage_counters, gboolean * config_changed,
210 xmlNode * current_cib, xmlNode ** result_cib, xmlNode ** diff, xmlNode ** output)
211 {
212 int rc = pcmk_ok;
213 gboolean check_schema = TRUE;
214 xmlNode *top = NULL;
215 xmlNode *scratch = NULL;
216 xmlNode *local_diff = NULL;
217
218 const char *new_version = NULL;
219 static struct qb_log_callsite *diff_cs = NULL;
220 const char *user = crm_element_value(req, F_CIB_USER);
221 bool with_digest = FALSE;
222
223 crm_trace("Begin %s%s%s op",
224 (pcmk_is_set(call_options, cib_dryrun)? "dry run of " : ""),
225 (is_query? "read-only " : ""), op);
226
227 CRM_CHECK(output != NULL, return -ENOMSG);
228 CRM_CHECK(result_cib != NULL, return -ENOMSG);
229 CRM_CHECK(config_changed != NULL, return -ENOMSG);
230
231 if(output) {
232 *output = NULL;
233 }
234
235 *result_cib = NULL;
236 *config_changed = FALSE;
237
238 if (fn == NULL) {
239 return -EINVAL;
240 }
241
242 if (is_query) {
243 xmlNode *cib_ro = current_cib;
244 xmlNode *cib_filtered = NULL;
245
246 if(cib_acl_enabled(cib_ro, user)) {
247 if(xml_acl_filtered_copy(user, current_cib, current_cib, &cib_filtered)) {
248 if (cib_filtered == NULL) {
249 crm_debug("Pre-filtered the entire cib");
250 return -EACCES;
251 }
252 cib_ro = cib_filtered;
253 crm_log_xml_trace(cib_ro, "filtered");
254 }
255 }
256
257 rc = (*fn) (op, call_options, section, req, input, cib_ro, result_cib, output);
258
259 if(output == NULL || *output == NULL) {
260
261
262 } else if(cib_filtered == *output) {
263 cib_filtered = NULL;
264
265 } else if(*output == current_cib) {
266
267
268 } else if(cib_filtered && (*output)->doc == cib_filtered->doc) {
269
270 *output = copy_xml(*output);
271
272 } else if((*output)->doc == current_cib->doc) {
273
274 *output = copy_xml(*output);
275 }
276
277 free_xml(cib_filtered);
278 return rc;
279 }
280
281
282 if (pcmk_is_set(call_options, cib_zero_copy)) {
283
284
285 scratch = current_cib;
286
287
288 current_cib = create_xml_node(NULL, (const char *)scratch->name);
289 copy_in_properties(current_cib, scratch);
290 top = current_cib;
291
292 xml_track_changes(scratch, user, NULL, cib_acl_enabled(scratch, user));
293 rc = (*fn) (op, call_options, section, req, input, scratch, &scratch, output);
294
295 } else {
296 scratch = copy_xml(current_cib);
297 xml_track_changes(scratch, user, NULL, cib_acl_enabled(scratch, user));
298 rc = (*fn) (op, call_options, section, req, input, current_cib, &scratch, output);
299
300 if(scratch && xml_tracking_changes(scratch) == FALSE) {
301 crm_trace("Inferring changes after %s op", op);
302 xml_track_changes(scratch, user, current_cib, cib_acl_enabled(current_cib, user));
303 xml_calculate_changes(current_cib, scratch);
304 }
305 CRM_CHECK(current_cib != scratch, return -EINVAL);
306 }
307
308 xml_acl_disable(scratch);
309
310 if (rc == pcmk_ok && scratch == NULL) {
311 rc = -EINVAL;
312 goto done;
313
314 } else if(rc == pcmk_ok && xml_acl_denied(scratch)) {
315 crm_trace("ACL rejected part or all of the proposed changes");
316 rc = -EACCES;
317 goto done;
318
319 } else if (rc != pcmk_ok) {
320 goto done;
321 }
322
323 if (scratch) {
324 new_version = crm_element_value(scratch, XML_ATTR_CRM_VERSION);
325
326 if (new_version && compare_version(new_version, CRM_FEATURE_SET) > 0) {
327 crm_err("Discarding update with feature set '%s' greater than our own '%s'",
328 new_version, CRM_FEATURE_SET);
329 rc = -EPROTONOSUPPORT;
330 goto done;
331 }
332 }
333
334 if (current_cib) {
335 int old = 0;
336 int new = 0;
337
338 crm_element_value_int(scratch, XML_ATTR_GENERATION_ADMIN, &new);
339 crm_element_value_int(current_cib, XML_ATTR_GENERATION_ADMIN, &old);
340
341 if (old > new) {
342 crm_err("%s went backwards: %d -> %d (Opts: 0x%x)",
343 XML_ATTR_GENERATION_ADMIN, old, new, call_options);
344 crm_log_xml_warn(req, "Bad Op");
345 crm_log_xml_warn(input, "Bad Data");
346 rc = -pcmk_err_old_data;
347
348 } else if (old == new) {
349 crm_element_value_int(scratch, XML_ATTR_GENERATION, &new);
350 crm_element_value_int(current_cib, XML_ATTR_GENERATION, &old);
351 if (old > new) {
352 crm_err("%s went backwards: %d -> %d (Opts: 0x%x)",
353 XML_ATTR_GENERATION, old, new, call_options);
354 crm_log_xml_warn(req, "Bad Op");
355 crm_log_xml_warn(input, "Bad Data");
356 rc = -pcmk_err_old_data;
357 }
358 }
359 }
360
361 crm_trace("Massaging CIB contents");
362 pcmk__strip_xml_text(scratch);
363 fix_plus_plus_recursive(scratch);
364
365 if (pcmk_is_set(call_options, cib_zero_copy)) {
366
367
368
369
370
371 local_diff = xml_create_patchset(2, current_cib, scratch, (bool*)config_changed, manage_counters);
372
373 } else {
374 static time_t expires = 0;
375 time_t tm_now = time(NULL);
376
377 if (expires < tm_now) {
378 expires = tm_now + 60;
379 with_digest = TRUE;
380 }
381
382 local_diff = xml_create_patchset(0, current_cib, scratch, (bool*)config_changed, manage_counters);
383 }
384
385 xml_log_changes(LOG_TRACE, __func__, scratch);
386 xml_accept_changes(scratch);
387
388 if (diff_cs == NULL) {
389 diff_cs = qb_log_callsite_get(__PRETTY_FUNCTION__, __FILE__, "diff-validation", LOG_DEBUG, __LINE__, crm_trace_nonlog);
390 }
391
392 if(local_diff) {
393 patchset_process_digest(local_diff, current_cib, scratch, with_digest);
394
395 xml_log_patchset(LOG_INFO, __func__, local_diff);
396 crm_log_xml_trace(local_diff, "raw patch");
397 }
398
399 if (!pcmk_is_set(call_options, cib_zero_copy)
400 && local_diff
401 && crm_is_callsite_active(diff_cs, LOG_TRACE, 0)) {
402
403
404 int test_rc, format = 1;
405 xmlNode * c = copy_xml(current_cib);
406
407 crm_element_value_int(local_diff, "format", &format);
408 test_rc = xml_apply_patchset(c, local_diff, manage_counters);
409
410 if(test_rc != pcmk_ok) {
411 save_xml_to_file(c, "PatchApply:calculated", NULL);
412 save_xml_to_file(current_cib, "PatchApply:input", NULL);
413 save_xml_to_file(scratch, "PatchApply:actual", NULL);
414 save_xml_to_file(local_diff, "PatchApply:diff", NULL);
415 crm_err("v%d patchset error, patch failed to apply: %s (%d)", format, pcmk_strerror(test_rc), test_rc);
416 }
417 free_xml(c);
418 }
419
420 if (pcmk__str_eq(section, XML_CIB_TAG_STATUS, pcmk__str_casei)) {
421
422
423
424
425 check_schema = FALSE;
426 }
427
428
429
430
431
432
433
434
435
436
437
438
439
440 if (*config_changed && !pcmk_is_set(call_options, cib_no_mtime)) {
441 const char *schema = crm_element_value(scratch, XML_ATTR_VALIDATION);
442
443 pcmk__xe_add_last_written(scratch);
444 if (schema) {
445 static int minimum_schema = 0;
446 int current_schema = get_schema_version(schema);
447
448 if (minimum_schema == 0) {
449 minimum_schema = get_schema_version("pacemaker-1.2");
450 }
451
452
453 if (current_schema >= minimum_schema) {
454 const char *origin = crm_element_value(req, F_ORIG);
455
456 CRM_LOG_ASSERT(origin != NULL);
457 crm_xml_replace(scratch, XML_ATTR_UPDATE_ORIG, origin);
458 crm_xml_replace(scratch, XML_ATTR_UPDATE_CLIENT,
459 crm_element_value(req, F_CIB_CLIENTNAME));
460 #if ENABLE_ACL
461 crm_xml_replace(scratch, XML_ATTR_UPDATE_USER, crm_element_value(req, F_CIB_USER));
462 #endif
463 }
464 }
465 }
466
467 crm_trace("Perform validation: %s", pcmk__btoa(check_schema));
468 if ((rc == pcmk_ok) && check_schema && !validate_xml(scratch, NULL, TRUE)) {
469 const char *current_schema = crm_element_value(scratch,
470 XML_ATTR_VALIDATION);
471
472 crm_warn("Updated CIB does not validate against %s schema",
473 crm_str(current_schema));
474 rc = -pcmk_err_schema_validation;
475 }
476
477 done:
478
479 *result_cib = scratch;
480 #if ENABLE_ACL
481 if(rc != pcmk_ok && cib_acl_enabled(current_cib, user)) {
482 if(xml_acl_filtered_copy(user, current_cib, scratch, result_cib)) {
483 if (*result_cib == NULL) {
484 crm_debug("Pre-filtered the entire cib result");
485 }
486 free_xml(scratch);
487 }
488 }
489 #endif
490
491 if(diff) {
492 *diff = local_diff;
493 } else {
494 free_xml(local_diff);
495 }
496
497 free_xml(top);
498 crm_trace("Done");
499 return rc;
500 }
501
502 xmlNode *
503 cib_create_op(int call_id, const char *token, const char *op, const char *host, const char *section,
504 xmlNode * data, int call_options, const char *user_name)
505 {
506 xmlNode *op_msg = create_xml_node(NULL, "cib_command");
507
508 CRM_CHECK(op_msg != NULL, return NULL);
509 CRM_CHECK(token != NULL, return NULL);
510
511 crm_xml_add(op_msg, F_XML_TAGNAME, "cib_command");
512
513 crm_xml_add(op_msg, F_TYPE, T_CIB);
514 crm_xml_add(op_msg, F_CIB_CALLBACK_TOKEN, token);
515 crm_xml_add(op_msg, F_CIB_OPERATION, op);
516 crm_xml_add(op_msg, F_CIB_HOST, host);
517 crm_xml_add(op_msg, F_CIB_SECTION, section);
518 crm_xml_add_int(op_msg, F_CIB_CALLID, call_id);
519 #if ENABLE_ACL
520 if (user_name) {
521 crm_xml_add(op_msg, F_CIB_USER, user_name);
522 }
523 #endif
524 crm_trace("Sending call options: %.8lx, %d", (long)call_options, call_options);
525 crm_xml_add_int(op_msg, F_CIB_CALLOPTS, call_options);
526
527 if (data != NULL) {
528 add_message_xml(op_msg, F_CIB_CALLDATA, data);
529 }
530
531 if (call_options & cib_inhibit_bcast) {
532 CRM_CHECK((call_options & cib_scope_local), return NULL);
533 }
534 return op_msg;
535 }
536
537 void
538 cib_native_callback(cib_t * cib, xmlNode * msg, int call_id, int rc)
539 {
540 xmlNode *output = NULL;
541 cib_callback_client_t *blob = NULL;
542
543 if (msg != NULL) {
544 crm_element_value_int(msg, F_CIB_RC, &rc);
545 crm_element_value_int(msg, F_CIB_CALLID, &call_id);
546 output = get_message_xml(msg, F_CIB_CALLDATA);
547 }
548
549 blob = g_hash_table_lookup(cib_op_callback_table, GINT_TO_POINTER(call_id));
550 if (blob == NULL) {
551 crm_trace("No callback found for call %d", call_id);
552 }
553
554 if (cib == NULL) {
555 crm_debug("No cib object supplied");
556 }
557
558 if (rc == -pcmk_err_diff_resync) {
559
560 rc = pcmk_ok;
561 }
562
563 if (blob && blob->callback && (rc == pcmk_ok || blob->only_success == FALSE)) {
564 crm_trace("Invoking callback %s for call %d", crm_str(blob->id), call_id);
565 blob->callback(msg, call_id, rc, output, blob->user_data);
566
567 } else if (cib && cib->op_callback == NULL && rc != pcmk_ok) {
568 crm_warn("CIB command failed: %s", pcmk_strerror(rc));
569 crm_log_xml_debug(msg, "Failed CIB Update");
570 }
571
572
573 if (blob) {
574 remove_cib_op_callback(call_id, FALSE);
575 }
576
577 if (cib && cib->op_callback != NULL) {
578 crm_trace("Invoking global callback for call %d", call_id);
579 cib->op_callback(msg, call_id, rc, output);
580 }
581 crm_trace("OP callback activated for %d", call_id);
582 }
583
584 void
585 cib_native_notify(gpointer data, gpointer user_data)
586 {
587 xmlNode *msg = user_data;
588 cib_notify_client_t *entry = data;
589 const char *event = NULL;
590
591 if (msg == NULL) {
592 crm_warn("Skipping callback - NULL message");
593 return;
594 }
595
596 event = crm_element_value(msg, F_SUBTYPE);
597
598 if (entry == NULL) {
599 crm_warn("Skipping callback - NULL callback client");
600 return;
601
602 } else if (entry->callback == NULL) {
603 crm_warn("Skipping callback - NULL callback");
604 return;
605
606 } else if (!pcmk__str_eq(entry->event, event, pcmk__str_casei)) {
607 crm_trace("Skipping callback - event mismatch %p/%s vs. %s", entry, entry->event, event);
608 return;
609 }
610
611 crm_trace("Invoking callback for %p/%s event...", entry, event);
612 entry->callback(event, msg);
613 crm_trace("Callback invoked...");
614 }
615
616 static pcmk__cluster_option_t cib_opts[] = {
617
618
619
620
621
622 {
623 "enable-acl", NULL, "boolean", NULL,
624 "false", pcmk__valid_boolean,
625 "Enable Access Control Lists (ACLs) for the CIB",
626 NULL
627 },
628 {
629 "cluster-ipc-limit", NULL, "integer", NULL,
630 "500", pcmk__valid_positive_number,
631 "Maximum IPC message backlog before disconnecting a cluster daemon",
632 "Raise this if log has \"Evicting client\" messages for cluster daemon"
633 " PIDs (a good value is the number of resources in the cluster"
634 " multiplied by the number of nodes)."
635 },
636 };
637
638 void
639 cib_metadata(void)
640 {
641 pcmk__print_option_metadata("pacemaker-based", "1.0",
642 "Cluster Information Base manager options",
643 "Cluster options used by Pacemaker's "
644 "Cluster Information Base manager",
645 cib_opts, DIMOF(cib_opts));
646 }
647
648 void
649 verify_cib_options(GHashTable * options)
650 {
651 pcmk__validate_cluster_options(options, cib_opts, DIMOF(cib_opts));
652 }
653
654 const char *
655 cib_pref(GHashTable * options, const char *name)
656 {
657 return pcmk__cluster_option(options, cib_opts, DIMOF(cib_opts), name);
658 }
659
660 gboolean
661 cib_read_config(GHashTable * options, xmlNode * current_cib)
662 {
663 xmlNode *config = NULL;
664 crm_time_t *now = NULL;
665
666 if (options == NULL || current_cib == NULL) {
667 return FALSE;
668 }
669
670 now = crm_time_new(NULL);
671
672 g_hash_table_remove_all(options);
673
674 config = get_object_root(XML_CIB_TAG_CRMCONFIG, current_cib);
675 if (config) {
676 pe_unpack_nvpairs(current_cib, config, XML_CIB_TAG_PROPSET, NULL,
677 options, CIB_OPTIONS_FIRST, TRUE, now, NULL);
678 }
679
680 verify_cib_options(options);
681
682 crm_time_free(now);
683
684 return TRUE;
685 }
686
687
688 #define XPATH_CONFIG_CHANGE \
689 "//" XML_CIB_TAG_CRMCONFIG " | " \
690 "//" XML_DIFF_CHANGE "[contains(@" XML_DIFF_PATH ",'/" XML_CIB_TAG_CRMCONFIG "/')]"
691
692 gboolean
693 cib_internal_config_changed(xmlNode *diff)
694 {
695 gboolean changed = FALSE;
696
697 if (diff) {
698 xmlXPathObject *xpathObj = xpath_search(diff, XPATH_CONFIG_CHANGE);
699
700 if (numXpathResults(xpathObj) > 0) {
701 changed = TRUE;
702 }
703 freeXpathObject(xpathObj);
704 }
705 return changed;
706 }
707
708 int
709 cib_internal_op(cib_t * cib, const char *op, const char *host,
710 const char *section, xmlNode * data,
711 xmlNode ** output_data, int call_options, const char *user_name)
712 {
713 int (*delegate) (cib_t * cib, const char *op, const char *host,
714 const char *section, xmlNode * data,
715 xmlNode ** output_data, int call_options, const char *user_name) =
716 cib->delegate_fn;
717
718 #if ENABLE_ACL
719 if(user_name == NULL) {
720 user_name = getenv("CIB_user");
721 }
722 #endif
723
724 return delegate(cib, op, host, section, data, output_data, call_options, user_name);
725 }
726
727
728 int cib_apply_patch_event(xmlNode *event, xmlNode *input, xmlNode **output,
729 int level);
730
731
732
733
734 int
735 cib_apply_patch_event(xmlNode *event, xmlNode *input, xmlNode **output,
736 int level)
737 {
738 int rc = pcmk_err_generic;
739
740 xmlNode *diff = NULL;
741
742 CRM_ASSERT(event);
743 CRM_ASSERT(input);
744 CRM_ASSERT(output);
745
746 crm_element_value_int(event, F_CIB_RC, &rc);
747 diff = get_message_xml(event, F_CIB_UPDATE_RESULT);
748
749 if (rc < pcmk_ok || diff == NULL) {
750 return rc;
751 }
752
753 if (level > LOG_CRIT) {
754 xml_log_patchset(level, "Config update", diff);
755 }
756
757 if (input != NULL) {
758 rc = cib_process_diff(NULL, cib_none, NULL, event, diff, input, output,
759 NULL);
760
761 if (rc != pcmk_ok) {
762 crm_debug("Update didn't apply: %s (%d) %p",
763 pcmk_strerror(rc), rc, *output);
764
765 if (rc == -pcmk_err_old_data) {
766 crm_trace("Masking error, we already have the supplied update");
767 return pcmk_ok;
768 }
769 free_xml(*output);
770 *output = NULL;
771 return rc;
772 }
773 }
774 return rc;
775 }