This source file includes following definitions.
- cib_version_details
- cib_diff_version_details
- cib__get_notify_patchset
- element_in_patchset_v1
- element_in_patchset_v2
- cib__element_in_patchset
- createEmptyCib
- cib_acl_enabled
- should_copy_cib
- cib_perform_op
- cib__create_op
- validate_transaction_request
- cib__extend_transaction
- cib_native_callback
- cib_native_notify
- cib_read_config
- cib_internal_op
- cib_apply_patch_event
- cib__signon_query
- cib__signon_attempts
- cib__clean_up_connection
- cib_get_generation
- get_object_path
- get_object_parent
- get_object_root
- cib_pref
- cib_metadata
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/common/cib_internal.h>
23 #include <crm/common/xml.h>
24 #include <crm/common/xml_internal.h>
25 #include <crm/pengine/rules.h>
26
27 gboolean
28 cib_version_details(xmlNode * cib, int *admin_epoch, int *epoch, int *updates)
29 {
30 *epoch = -1;
31 *updates = -1;
32 *admin_epoch = -1;
33
34 if (cib == NULL) {
35 return FALSE;
36
37 } else {
38 crm_element_value_int(cib, PCMK_XA_EPOCH, epoch);
39 crm_element_value_int(cib, PCMK_XA_NUM_UPDATES, updates);
40 crm_element_value_int(cib, PCMK_XA_ADMIN_EPOCH, admin_epoch);
41 }
42 return TRUE;
43 }
44
45 gboolean
46 cib_diff_version_details(xmlNode * diff, int *admin_epoch, int *epoch, int *updates,
47 int *_admin_epoch, int *_epoch, int *_updates)
48 {
49 int add[] = { 0, 0, 0 };
50 int del[] = { 0, 0, 0 };
51
52 xml_patch_versions(diff, add, del);
53
54 *admin_epoch = add[0];
55 *epoch = add[1];
56 *updates = add[2];
57
58 *_admin_epoch = del[0];
59 *_epoch = del[1];
60 *_updates = del[2];
61
62 return TRUE;
63 }
64
65
66
67
68
69
70
71
72
73
74 int
75 cib__get_notify_patchset(const xmlNode *msg, const xmlNode **patchset)
76 {
77 int rc = pcmk_err_generic;
78 xmlNode *wrapper = NULL;
79
80 pcmk__assert(patchset != NULL);
81 *patchset = NULL;
82
83 if (msg == NULL) {
84 crm_err("CIB diff notification received with no XML");
85 return ENOMSG;
86 }
87
88 if ((crm_element_value_int(msg, PCMK__XA_CIB_RC, &rc) != 0)
89 || (rc != pcmk_ok)) {
90
91 crm_warn("Ignore failed CIB update: %s " CRM_XS " rc=%d",
92 pcmk_strerror(rc), rc);
93 crm_log_xml_debug(msg, "failed");
94 return pcmk_legacy2rc(rc);
95 }
96
97 wrapper = pcmk__xe_first_child(msg, PCMK__XE_CIB_UPDATE_RESULT, NULL, NULL);
98 *patchset = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
99
100 if (*patchset == NULL) {
101 crm_err("CIB diff notification received with no patchset");
102 return ENOMSG;
103 }
104 return pcmk_rc_ok;
105 }
106
107 #define XPATH_DIFF_V1 "//" PCMK__XE_CIB_UPDATE_RESULT "//" PCMK__XE_DIFF_ADDED
108
109
110
111
112
113
114
115
116
117
118
119 static bool
120 element_in_patchset_v1(const xmlNode *patchset, const char *element)
121 {
122 char *xpath = crm_strdup_printf(XPATH_DIFF_V1 "//%s",
123 pcmk__s(element, PCMK_XE_CIB));
124 xmlXPathObject *xpath_obj = xpath_search(patchset, xpath);
125
126 free(xpath);
127
128 if (xpath_obj == NULL) {
129 return false;
130 }
131 freeXpathObject(xpath_obj);
132 return true;
133 }
134
135
136
137
138
139
140
141
142
143
144
145
146 static bool
147 element_in_patchset_v2(const xmlNode *patchset, const char *element)
148 {
149 const char *element_xpath = pcmk__cib_abs_xpath_for(element);
150 const char *parent_xpath = pcmk_cib_parent_name_for(element);
151 char *element_regex = NULL;
152 bool rc = false;
153
154 CRM_CHECK(element_xpath != NULL, return false);
155
156
157 element_regex = crm_strdup_printf("^%s(/|$)", element_xpath);
158
159 for (const xmlNode *change = pcmk__xe_first_child(patchset, PCMK_XE_CHANGE,
160 NULL, NULL);
161 change != NULL; change = pcmk__xe_next_same(change)) {
162
163 const char *op = crm_element_value(change, PCMK_XA_OPERATION);
164 const char *diff_xpath = crm_element_value(change, PCMK_XA_PATH);
165
166 if (pcmk__str_eq(diff_xpath, element_regex, pcmk__str_regex)) {
167
168 rc = true;
169 break;
170 }
171
172 if (pcmk__str_eq(op, PCMK_VALUE_CREATE, pcmk__str_none)
173 && pcmk__str_eq(diff_xpath, parent_xpath, pcmk__str_none)
174 && pcmk__xe_is(pcmk__xe_first_child(change, NULL, NULL, NULL),
175 element)) {
176
177
178 rc = true;
179 break;
180 }
181 }
182
183 free(element_regex);
184 return rc;
185 }
186
187
188
189
190
191
192
193
194
195
196
197
198 bool
199 cib__element_in_patchset(const xmlNode *patchset, const char *element)
200 {
201 int format = 1;
202
203 pcmk__assert(patchset != NULL);
204
205 crm_element_value_int(patchset, PCMK_XA_FORMAT, &format);
206 switch (format) {
207 case 1:
208 return element_in_patchset_v1(patchset, element);
209
210 case 2:
211 return element_in_patchset_v2(patchset, element);
212
213 default:
214 crm_warn("Unknown patch format: %d", format);
215 return false;
216 }
217 }
218
219
220
221
222
223
224
225
226
227 xmlNode *
228 createEmptyCib(int cib_epoch)
229 {
230 xmlNode *cib_root = NULL, *config = NULL;
231
232 cib_root = pcmk__xe_create(NULL, PCMK_XE_CIB);
233 crm_xml_add(cib_root, PCMK_XA_CRM_FEATURE_SET, CRM_FEATURE_SET);
234 crm_xml_add(cib_root, PCMK_XA_VALIDATE_WITH, pcmk__highest_schema_name());
235
236 crm_xml_add_int(cib_root, PCMK_XA_EPOCH, cib_epoch);
237 crm_xml_add_int(cib_root, PCMK_XA_NUM_UPDATES, 0);
238 crm_xml_add_int(cib_root, PCMK_XA_ADMIN_EPOCH, 0);
239
240 config = pcmk__xe_create(cib_root, PCMK_XE_CONFIGURATION);
241 pcmk__xe_create(cib_root, PCMK_XE_STATUS);
242
243 pcmk__xe_create(config, PCMK_XE_CRM_CONFIG);
244 pcmk__xe_create(config, PCMK_XE_NODES);
245 pcmk__xe_create(config, PCMK_XE_RESOURCES);
246 pcmk__xe_create(config, PCMK_XE_CONSTRAINTS);
247
248 #if PCMK__RESOURCE_STICKINESS_DEFAULT != 0
249 {
250 xmlNode *rsc_defaults = pcmk__xe_create(config, PCMK_XE_RSC_DEFAULTS);
251 xmlNode *meta = pcmk__xe_create(rsc_defaults, PCMK_XE_META_ATTRIBUTES);
252 xmlNode *nvpair = pcmk__xe_create(meta, PCMK_XE_NVPAIR);
253
254 crm_xml_add(meta, PCMK_XA_ID, "build-resource-defaults");
255 crm_xml_add(nvpair, PCMK_XA_ID, "build-" PCMK_META_RESOURCE_STICKINESS);
256 crm_xml_add(nvpair, PCMK_XA_NAME, PCMK_META_RESOURCE_STICKINESS);
257 crm_xml_add_int(nvpair, PCMK_XA_VALUE,
258 PCMK__RESOURCE_STICKINESS_DEFAULT);
259 }
260 #endif
261 return cib_root;
262 }
263
264 static bool
265 cib_acl_enabled(xmlNode *xml, const char *user)
266 {
267 bool rc = FALSE;
268
269 if(pcmk_acl_required(user)) {
270 const char *value = NULL;
271 GHashTable *options = pcmk__strkey_table(free, free);
272
273 cib_read_config(options, xml);
274 value = pcmk__cluster_option(options, PCMK_OPT_ENABLE_ACL);
275 rc = crm_is_true(value);
276 g_hash_table_destroy(options);
277 }
278
279 crm_trace("CIB ACL is %s", rc ? "enabled" : "disabled");
280 return rc;
281 }
282
283
284
285
286
287
288
289
290
291
292
293 static bool
294 should_copy_cib(const char *op, const char *section, int call_options)
295 {
296 if (pcmk_is_set(call_options, cib_dryrun)) {
297
298 return true;
299 }
300
301 if (pcmk__str_eq(op, PCMK__CIB_REQUEST_COMMIT_TRANSACT, pcmk__str_none)) {
302
303
304
305
306 return true;
307 }
308
309 if (pcmk_is_set(call_options, cib_transaction)) {
310
311
312
313
314 return false;
315 }
316
317 if (pcmk__str_eq(section, PCMK_XE_STATUS, pcmk__str_none)) {
318
319
320
321
322
323
324 return false;
325 }
326
327
328 return true;
329 }
330
331 int
332 cib_perform_op(cib_t *cib, const char *op, uint32_t call_options,
333 cib__op_fn_t fn, bool is_query, const char *section,
334 xmlNode *req, xmlNode *input, bool manage_counters,
335 bool *config_changed, xmlNode **current_cib,
336 xmlNode **result_cib, xmlNode **diff, xmlNode **output)
337 {
338 int rc = pcmk_ok;
339 bool check_schema = true;
340 bool make_copy = true;
341 xmlNode *top = NULL;
342 xmlNode *scratch = NULL;
343 xmlNode *patchset_cib = NULL;
344 xmlNode *local_diff = NULL;
345
346 const char *user = crm_element_value(req, PCMK__XA_CIB_USER);
347 bool with_digest = false;
348
349 crm_trace("Begin %s%s%s op",
350 (pcmk_is_set(call_options, cib_dryrun)? "dry run of " : ""),
351 (is_query? "read-only " : ""), op);
352
353 CRM_CHECK(output != NULL, return -ENOMSG);
354 CRM_CHECK(current_cib != NULL, return -ENOMSG);
355 CRM_CHECK(result_cib != NULL, return -ENOMSG);
356 CRM_CHECK(config_changed != NULL, return -ENOMSG);
357
358 if(output) {
359 *output = NULL;
360 }
361
362 *result_cib = NULL;
363 *config_changed = false;
364
365 if (fn == NULL) {
366 return -EINVAL;
367 }
368
369 if (is_query) {
370 xmlNode *cib_ro = *current_cib;
371 xmlNode *cib_filtered = NULL;
372
373 if (cib_acl_enabled(cib_ro, user)
374 && xml_acl_filtered_copy(user, *current_cib, *current_cib,
375 &cib_filtered)) {
376
377 if (cib_filtered == NULL) {
378 crm_debug("Pre-filtered the entire cib");
379 return -EACCES;
380 }
381 cib_ro = cib_filtered;
382 crm_log_xml_trace(cib_ro, "filtered");
383 }
384
385 rc = (*fn) (op, call_options, section, req, input, cib_ro, result_cib, output);
386
387 if(output == NULL || *output == NULL) {
388
389
390 } else if(cib_filtered == *output) {
391 cib_filtered = NULL;
392
393 } else if (*output == *current_cib) {
394
395
396 } else if(cib_filtered && (*output)->doc == cib_filtered->doc) {
397
398 *output = pcmk__xml_copy(NULL, *output);
399
400 } else if ((*output)->doc == (*current_cib)->doc) {
401
402 *output = pcmk__xml_copy(NULL, *output);
403 }
404
405 free_xml(cib_filtered);
406 return rc;
407 }
408
409 make_copy = should_copy_cib(op, section, call_options);
410
411 if (!make_copy) {
412
413
414 scratch = *current_cib;
415
416
417 top = pcmk__xe_create(NULL, (const char *) scratch->name);
418 pcmk__xe_copy_attrs(top, scratch, pcmk__xaf_none);
419 patchset_cib = top;
420
421 xml_track_changes(scratch, user, NULL, cib_acl_enabled(scratch, user));
422 rc = (*fn) (op, call_options, section, req, input, scratch, &scratch, output);
423
424
425
426
427 *current_cib = scratch;
428
429 } else {
430 scratch = pcmk__xml_copy(NULL, *current_cib);
431 patchset_cib = *current_cib;
432
433 xml_track_changes(scratch, user, NULL, cib_acl_enabled(scratch, user));
434 rc = (*fn) (op, call_options, section, req, input, *current_cib,
435 &scratch, output);
436
437 if ((scratch != NULL) && !xml_tracking_changes(scratch)) {
438 crm_trace("Inferring changes after %s op", op);
439 xml_track_changes(scratch, user, *current_cib,
440 cib_acl_enabled(*current_cib, user));
441 xml_calculate_changes(*current_cib, scratch);
442 }
443 CRM_CHECK(*current_cib != scratch, return -EINVAL);
444 }
445
446 xml_acl_disable(scratch);
447
448 if (rc == pcmk_ok && scratch == NULL) {
449 rc = -EINVAL;
450 goto done;
451
452 } else if(rc == pcmk_ok && xml_acl_denied(scratch)) {
453 crm_trace("ACL rejected part or all of the proposed changes");
454 rc = -EACCES;
455 goto done;
456
457 } else if (rc != pcmk_ok) {
458 goto done;
459 }
460
461
462
463
464
465 if (scratch && (cib == NULL || cib->variant != cib_file)) {
466 const char *new_version = crm_element_value(scratch, PCMK_XA_CRM_FEATURE_SET);
467
468 rc = pcmk__check_feature_set(new_version);
469 if (rc != pcmk_rc_ok) {
470 pcmk__config_err("Discarding update with feature set '%s' greater than our own '%s'",
471 new_version, CRM_FEATURE_SET);
472 rc = pcmk_rc2legacy(rc);
473 goto done;
474 }
475 }
476
477 if (patchset_cib != NULL) {
478 int old = 0;
479 int new = 0;
480
481 crm_element_value_int(scratch, PCMK_XA_ADMIN_EPOCH, &new);
482 crm_element_value_int(patchset_cib, PCMK_XA_ADMIN_EPOCH, &old);
483
484 if (old > new) {
485 crm_err("%s went backwards: %d -> %d (Opts: %#x)",
486 PCMK_XA_ADMIN_EPOCH, old, new, call_options);
487 crm_log_xml_warn(req, "Bad Op");
488 crm_log_xml_warn(input, "Bad Data");
489 rc = -pcmk_err_old_data;
490
491 } else if (old == new) {
492 crm_element_value_int(scratch, PCMK_XA_EPOCH, &new);
493 crm_element_value_int(patchset_cib, PCMK_XA_EPOCH, &old);
494 if (old > new) {
495 crm_err("%s went backwards: %d -> %d (Opts: %#x)",
496 PCMK_XA_EPOCH, old, new, call_options);
497 crm_log_xml_warn(req, "Bad Op");
498 crm_log_xml_warn(input, "Bad Data");
499 rc = -pcmk_err_old_data;
500 }
501 }
502 }
503
504 crm_trace("Massaging CIB contents");
505 pcmk__strip_xml_text(scratch);
506
507 if (!make_copy) {
508
509
510
511
512
513
514 local_diff = xml_create_patchset(2, patchset_cib, scratch,
515 config_changed, manage_counters);
516
517 } else {
518 static time_t expires = 0;
519 time_t tm_now = time(NULL);
520
521 if (expires < tm_now) {
522 expires = tm_now + 60;
523 with_digest = true;
524 }
525
526 local_diff = xml_create_patchset(0, patchset_cib, scratch,
527 config_changed, manage_counters);
528 }
529
530 pcmk__log_xml_changes(LOG_TRACE, scratch);
531 xml_accept_changes(scratch);
532
533 if(local_diff) {
534 patchset_process_digest(local_diff, patchset_cib, scratch, with_digest);
535 pcmk__log_xml_patchset(LOG_INFO, local_diff);
536 crm_log_xml_trace(local_diff, "raw patch");
537 }
538
539 if (make_copy && (local_diff != NULL)) {
540
541 pcmk__if_tracing(
542 {
543
544 int test_rc = pcmk_ok;
545 int format = 1;
546 xmlNode *cib_copy = pcmk__xml_copy(NULL, patchset_cib);
547
548 crm_element_value_int(local_diff, PCMK_XA_FORMAT, &format);
549 test_rc = xml_apply_patchset(cib_copy, local_diff,
550 manage_counters);
551
552 if (test_rc != pcmk_ok) {
553 save_xml_to_file(cib_copy, "PatchApply:calculated", NULL);
554 save_xml_to_file(patchset_cib, "PatchApply:input", NULL);
555 save_xml_to_file(scratch, "PatchApply:actual", NULL);
556 save_xml_to_file(local_diff, "PatchApply:diff", NULL);
557 crm_err("v%d patchset error, patch failed to apply: %s "
558 "(%d)",
559 format, pcmk_rc_str(pcmk_legacy2rc(test_rc)),
560 test_rc);
561 }
562 free_xml(cib_copy);
563 },
564 {}
565 );
566 }
567
568 if (pcmk__str_eq(section, PCMK_XE_STATUS, pcmk__str_casei)) {
569
570
571
572
573 check_schema = false;
574 }
575
576
577
578
579
580
581
582
583
584
585
586
587
588 if (*config_changed && !pcmk_is_set(call_options, cib_no_mtime)) {
589 const char *schema = crm_element_value(scratch, PCMK_XA_VALIDATE_WITH);
590
591 pcmk__xe_add_last_written(scratch);
592 pcmk__warn_if_schema_deprecated(schema);
593
594
595
596
597 if (pcmk__cmp_schemas_by_name(schema, "pacemaker-1.2") >= 0) {
598 const char *origin = crm_element_value(req, PCMK__XA_SRC);
599 const char *client = crm_element_value(req,
600 PCMK__XA_CIB_CLIENTNAME);
601
602 if (origin != NULL) {
603 crm_xml_add(scratch, PCMK_XA_UPDATE_ORIGIN, origin);
604 } else {
605 pcmk__xe_remove_attr(scratch, PCMK_XA_UPDATE_ORIGIN);
606 }
607
608 if (client != NULL) {
609 crm_xml_add(scratch, PCMK_XA_UPDATE_CLIENT, user);
610 } else {
611 pcmk__xe_remove_attr(scratch, PCMK_XA_UPDATE_CLIENT);
612 }
613
614 if (user != NULL) {
615 crm_xml_add(scratch, PCMK_XA_UPDATE_USER, user);
616 } else {
617 pcmk__xe_remove_attr(scratch, PCMK_XA_UPDATE_USER);
618 }
619 }
620 }
621
622 crm_trace("Perform validation: %s", pcmk__btoa(check_schema));
623 if ((rc == pcmk_ok) && check_schema
624 && !pcmk__configured_schema_validates(scratch)) {
625 const char *current_schema = crm_element_value(scratch,
626 PCMK_XA_VALIDATE_WITH);
627
628 crm_warn("Updated CIB does not validate against %s schema",
629 pcmk__s(current_schema, "unspecified"));
630 rc = -pcmk_err_schema_validation;
631 }
632
633 done:
634
635 *result_cib = scratch;
636
637
638
639
640 if ((rc != pcmk_ok) && cib_acl_enabled(patchset_cib, user)
641 && xml_acl_filtered_copy(user, patchset_cib, scratch, result_cib)) {
642
643 if (*result_cib == NULL) {
644 crm_debug("Pre-filtered the entire cib result");
645 }
646 free_xml(scratch);
647 }
648
649 if(diff) {
650 *diff = local_diff;
651 } else {
652 free_xml(local_diff);
653 }
654
655 free_xml(top);
656 crm_trace("Done");
657 return rc;
658 }
659
660 int
661 cib__create_op(cib_t *cib, const char *op, const char *host,
662 const char *section, xmlNode *data, int call_options,
663 const char *user_name, const char *client_name,
664 xmlNode **op_msg)
665 {
666 CRM_CHECK((cib != NULL) && (op_msg != NULL), return -EPROTO);
667
668 *op_msg = pcmk__xe_create(NULL, PCMK__XE_CIB_COMMAND);
669
670 cib->call_id++;
671 if (cib->call_id < 1) {
672 cib->call_id = 1;
673 }
674
675 crm_xml_add(*op_msg, PCMK__XA_T, PCMK__VALUE_CIB);
676 crm_xml_add(*op_msg, PCMK__XA_CIB_OP, op);
677 crm_xml_add(*op_msg, PCMK__XA_CIB_HOST, host);
678 crm_xml_add(*op_msg, PCMK__XA_CIB_SECTION, section);
679 crm_xml_add(*op_msg, PCMK__XA_CIB_USER, user_name);
680 crm_xml_add(*op_msg, PCMK__XA_CIB_CLIENTNAME, client_name);
681 crm_xml_add_int(*op_msg, PCMK__XA_CIB_CALLID, cib->call_id);
682
683 crm_trace("Sending call options: %.8lx, %d", (long)call_options, call_options);
684 crm_xml_add_int(*op_msg, PCMK__XA_CIB_CALLOPT, call_options);
685
686 if (data != NULL) {
687 xmlNode *wrapper = pcmk__xe_create(*op_msg, PCMK__XE_CIB_CALLDATA);
688
689 pcmk__xml_copy(wrapper, data);
690 }
691
692 if (pcmk_is_set(call_options, cib_inhibit_bcast)) {
693 CRM_CHECK(pcmk_is_set(call_options, cib_scope_local),
694 free_xml(*op_msg); return -EPROTO);
695 }
696 return pcmk_ok;
697 }
698
699
700
701
702
703
704
705
706
707 static int
708 validate_transaction_request(const xmlNode *request)
709 {
710 const char *op = crm_element_value(request, PCMK__XA_CIB_OP);
711 const char *host = crm_element_value(request, PCMK__XA_CIB_HOST);
712 const cib__operation_t *operation = NULL;
713 int rc = cib__get_operation(op, &operation);
714
715 if (rc != pcmk_rc_ok) {
716
717 return rc;
718 }
719
720 if (!pcmk_is_set(operation->flags, cib__op_attr_transaction)) {
721 crm_err("Operation %s is not supported in CIB transactions", op);
722 return EOPNOTSUPP;
723 }
724
725 if (host != NULL) {
726 crm_err("Operation targeting a specific node (%s) is not supported in "
727 "a CIB transaction",
728 host);
729 return EOPNOTSUPP;
730 }
731 return pcmk_rc_ok;
732 }
733
734
735
736
737
738
739
740
741
742
743 int
744 cib__extend_transaction(cib_t *cib, xmlNode *request)
745 {
746 int rc = pcmk_rc_ok;
747
748 pcmk__assert((cib != NULL) && (request != NULL));
749
750 rc = validate_transaction_request(request);
751
752 if ((rc == pcmk_rc_ok) && (cib->transaction == NULL)) {
753 rc = pcmk_rc_no_transaction;
754 }
755
756 if (rc == pcmk_rc_ok) {
757 pcmk__xml_copy(cib->transaction, request);
758
759 } else {
760 const char *op = crm_element_value(request, PCMK__XA_CIB_OP);
761 const char *client_id = NULL;
762
763 cib->cmds->client_id(cib, NULL, &client_id);
764 crm_err("Failed to add '%s' operation to transaction for client %s: %s",
765 op, pcmk__s(client_id, "(unidentified)"), pcmk_rc_str(rc));
766 crm_log_xml_info(request, "failed");
767 }
768 return pcmk_rc2legacy(rc);
769 }
770
771 void
772 cib_native_callback(cib_t * cib, xmlNode * msg, int call_id, int rc)
773 {
774 xmlNode *output = NULL;
775 cib_callback_client_t *blob = NULL;
776
777 if (msg != NULL) {
778 xmlNode *wrapper = NULL;
779
780 crm_element_value_int(msg, PCMK__XA_CIB_RC, &rc);
781 crm_element_value_int(msg, PCMK__XA_CIB_CALLID, &call_id);
782 wrapper = pcmk__xe_first_child(msg, PCMK__XE_CIB_CALLDATA, NULL, NULL);
783 output = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
784 }
785
786 blob = cib__lookup_id(call_id);
787
788 if (blob == NULL) {
789 crm_trace("No callback found for call %d", call_id);
790 }
791
792 if (cib == NULL) {
793 crm_debug("No cib object supplied");
794 }
795
796 if (rc == -pcmk_err_diff_resync) {
797
798 rc = pcmk_ok;
799 }
800
801 if (blob && blob->callback && (rc == pcmk_ok || blob->only_success == FALSE)) {
802 crm_trace("Invoking callback %s for call %d",
803 pcmk__s(blob->id, "without ID"), call_id);
804 blob->callback(msg, call_id, rc, output, blob->user_data);
805
806 } else if (cib && cib->op_callback == NULL && rc != pcmk_ok) {
807 crm_warn("CIB command failed: %s", pcmk_strerror(rc));
808 crm_log_xml_debug(msg, "Failed CIB Update");
809 }
810
811
812 if (blob) {
813 remove_cib_op_callback(call_id, FALSE);
814 }
815
816 if (cib && cib->op_callback != NULL) {
817 crm_trace("Invoking global callback for call %d", call_id);
818 cib->op_callback(msg, call_id, rc, output);
819 }
820 crm_trace("OP callback activated for %d", call_id);
821 }
822
823 void
824 cib_native_notify(gpointer data, gpointer user_data)
825 {
826 xmlNode *msg = user_data;
827 cib_notify_client_t *entry = data;
828 const char *event = NULL;
829
830 if (msg == NULL) {
831 crm_warn("Skipping callback - NULL message");
832 return;
833 }
834
835 event = crm_element_value(msg, PCMK__XA_SUBT);
836
837 if (entry == NULL) {
838 crm_warn("Skipping callback - NULL callback client");
839 return;
840
841 } else if (entry->callback == NULL) {
842 crm_warn("Skipping callback - NULL callback");
843 return;
844
845 } else if (!pcmk__str_eq(entry->event, event, pcmk__str_casei)) {
846 crm_trace("Skipping callback - event mismatch %p/%s vs. %s", entry, entry->event, event);
847 return;
848 }
849
850 crm_trace("Invoking callback for %p/%s event...", entry, event);
851 entry->callback(event, msg);
852 crm_trace("Callback invoked...");
853 }
854
855 gboolean
856 cib_read_config(GHashTable * options, xmlNode * current_cib)
857 {
858 xmlNode *config = NULL;
859 crm_time_t *now = NULL;
860
861 if (options == NULL || current_cib == NULL) {
862 return FALSE;
863 }
864
865 now = crm_time_new(NULL);
866
867 g_hash_table_remove_all(options);
868
869 config = pcmk_find_cib_element(current_cib, PCMK_XE_CRM_CONFIG);
870 if (config) {
871 pe_unpack_nvpairs(current_cib, config, PCMK_XE_CLUSTER_PROPERTY_SET,
872 NULL, options, PCMK_VALUE_CIB_BOOTSTRAP_OPTIONS, TRUE,
873 now, NULL);
874 }
875
876 pcmk__validate_cluster_options(options);
877
878 crm_time_free(now);
879
880 return TRUE;
881 }
882
883 int
884 cib_internal_op(cib_t * cib, const char *op, const char *host,
885 const char *section, xmlNode * data,
886 xmlNode ** output_data, int call_options, const char *user_name)
887 {
888 int (*delegate)(cib_t *cib, const char *op, const char *host,
889 const char *section, xmlNode *data, xmlNode **output_data,
890 int call_options, const char *user_name) = NULL;
891
892 if (cib == NULL) {
893 return -EINVAL;
894 }
895
896 delegate = cib->delegate_fn;
897 if (delegate == NULL) {
898 return -EPROTONOSUPPORT;
899 }
900 if (user_name == NULL) {
901 user_name = getenv("CIB_user");
902 }
903 return delegate(cib, op, host, section, data, output_data, call_options, user_name);
904 }
905
906
907
908
909
910
911
912
913
914
915
916
917 int
918 cib_apply_patch_event(xmlNode *event, xmlNode *input, xmlNode **output,
919 int level)
920 {
921 int rc = pcmk_err_generic;
922
923 xmlNode *wrapper = NULL;
924 xmlNode *diff = NULL;
925
926 pcmk__assert((event != NULL) && (input != NULL) && (output != NULL));
927
928 crm_element_value_int(event, PCMK__XA_CIB_RC, &rc);
929 wrapper = pcmk__xe_first_child(event, PCMK__XE_CIB_UPDATE_RESULT, NULL,
930 NULL);
931 diff = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
932
933 if (rc < pcmk_ok || diff == NULL) {
934 return rc;
935 }
936
937 if (level > LOG_CRIT) {
938 pcmk__log_xml_patchset(level, diff);
939 }
940
941 if (input != NULL) {
942 rc = cib_process_diff(NULL, cib_none, NULL, event, diff, input, output,
943 NULL);
944
945 if (rc != pcmk_ok) {
946 crm_debug("Update didn't apply: %s (%d) %p",
947 pcmk_strerror(rc), rc, *output);
948
949 if (rc == -pcmk_err_old_data) {
950 crm_trace("Masking error, we already have the supplied update");
951 return pcmk_ok;
952 }
953 free_xml(*output);
954 *output = NULL;
955 return rc;
956 }
957 }
958 return rc;
959 }
960
961 #define log_signon_query_err(out, fmt, args...) do { \
962 if (out != NULL) { \
963 out->err(out, fmt, ##args); \
964 } else { \
965 crm_err(fmt, ##args); \
966 } \
967 } while (0)
968
969 int
970 cib__signon_query(pcmk__output_t *out, cib_t **cib, xmlNode **cib_object)
971 {
972 int rc = pcmk_rc_ok;
973 cib_t *cib_conn = NULL;
974
975 pcmk__assert(cib_object != NULL);
976
977 if (cib == NULL) {
978 cib_conn = cib_new();
979 } else {
980 if (*cib == NULL) {
981 *cib = cib_new();
982 }
983 cib_conn = *cib;
984 }
985
986 if (cib_conn == NULL) {
987 return ENOMEM;
988 }
989
990 if (cib_conn->state == cib_disconnected) {
991 rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command);
992 rc = pcmk_legacy2rc(rc);
993 }
994
995 if (rc != pcmk_rc_ok) {
996 log_signon_query_err(out, "Could not connect to the CIB: %s",
997 pcmk_rc_str(rc));
998 goto done;
999 }
1000
1001 if (out != NULL) {
1002 out->transient(out, "Querying CIB...");
1003 }
1004 rc = cib_conn->cmds->query(cib_conn, NULL, cib_object,
1005 cib_scope_local|cib_sync_call);
1006 rc = pcmk_legacy2rc(rc);
1007
1008 if (rc != pcmk_rc_ok) {
1009 log_signon_query_err(out, "CIB query failed: %s", pcmk_rc_str(rc));
1010 }
1011
1012 done:
1013 if (cib == NULL) {
1014 cib__clean_up_connection(&cib_conn);
1015 }
1016
1017 if ((rc == pcmk_rc_ok) && (*cib_object == NULL)) {
1018 return pcmk_rc_no_input;
1019 }
1020 return rc;
1021 }
1022
1023 int
1024 cib__signon_attempts(cib_t *cib, const char *name, enum cib_conn_type type,
1025 int attempts)
1026 {
1027 int rc = pcmk_rc_ok;
1028
1029 crm_trace("Attempting connection to CIB manager (up to %d time%s)",
1030 attempts, pcmk__plural_s(attempts));
1031
1032 for (int remaining = attempts - 1; remaining >= 0; --remaining) {
1033 rc = cib->cmds->signon(cib, name, type);
1034
1035 if ((rc == pcmk_rc_ok)
1036 || (remaining == 0)
1037 || ((errno != EAGAIN) && (errno != EALREADY))) {
1038 break;
1039 }
1040
1041
1042 pcmk__sleep_ms((attempts - remaining) * 500);
1043 crm_debug("Re-attempting connection to CIB manager (%d attempt%s remaining)",
1044 remaining, pcmk__plural_s(remaining));
1045 }
1046
1047 return rc;
1048 }
1049
1050 int
1051 cib__clean_up_connection(cib_t **cib)
1052 {
1053 int rc;
1054
1055 if (*cib == NULL) {
1056 return pcmk_rc_ok;
1057 }
1058
1059 rc = (*cib)->cmds->signoff(*cib);
1060 cib_delete(*cib);
1061 *cib = NULL;
1062 return pcmk_legacy2rc(rc);
1063 }
1064
1065
1066
1067
1068 #include <crm/cib/util_compat.h>
1069
1070 xmlNode *
1071 cib_get_generation(cib_t * cib)
1072 {
1073 xmlNode *the_cib = NULL;
1074 xmlNode *generation = pcmk__xe_create(NULL, PCMK__XE_GENERATION_TUPLE);
1075
1076 cib->cmds->query(cib, NULL, &the_cib, cib_scope_local | cib_sync_call);
1077 if (the_cib != NULL) {
1078 pcmk__xe_copy_attrs(generation, the_cib, pcmk__xaf_none);
1079 free_xml(the_cib);
1080 }
1081
1082 return generation;
1083 }
1084
1085 const char *
1086 get_object_path(const char *object_type)
1087 {
1088 return pcmk_cib_xpath_for(object_type);
1089 }
1090
1091 const char *
1092 get_object_parent(const char *object_type)
1093 {
1094 return pcmk_cib_parent_name_for(object_type);
1095 }
1096
1097 xmlNode *
1098 get_object_root(const char *object_type, xmlNode *the_root)
1099 {
1100 return pcmk_find_cib_element(the_root, object_type);
1101 }
1102
1103 const char *
1104 cib_pref(GHashTable * options, const char *name)
1105 {
1106 return pcmk__cluster_option(options, name);
1107 }
1108
1109 void
1110 cib_metadata(void)
1111 {
1112 pcmk__output_t *out = NULL;
1113 int rc = pcmk__output_new(&out, "text", NULL, NULL);
1114
1115 if (rc != pcmk_rc_ok) {
1116 crm_err("Unable to output metadata: %s", pcmk_rc_str(rc));
1117 return;
1118 }
1119
1120 pcmk__daemon_metadata(out, "pacemaker-based",
1121 "Cluster Information Base manager options",
1122 "Cluster options used by Pacemaker's Cluster "
1123 "Information Base manager",
1124 pcmk__opt_based);
1125
1126 out->finish(out, CRM_EX_OK, true, NULL);
1127 pcmk__output_free(out);
1128 }
1129
1130
1131