This source file includes following definitions.
- cib_version_details
- cib_diff_version_details
- cib__get_notify_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
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 " QB_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
108
109
110
111
112
113
114
115
116
117 xmlNode *
118 createEmptyCib(int cib_epoch)
119 {
120 xmlNode *cib_root = NULL, *config = NULL;
121
122 cib_root = pcmk__xe_create(NULL, PCMK_XE_CIB);
123 crm_xml_add(cib_root, PCMK_XA_CRM_FEATURE_SET, CRM_FEATURE_SET);
124 crm_xml_add(cib_root, PCMK_XA_VALIDATE_WITH, pcmk__highest_schema_name());
125
126 crm_xml_add_int(cib_root, PCMK_XA_EPOCH, cib_epoch);
127 crm_xml_add_int(cib_root, PCMK_XA_NUM_UPDATES, 0);
128 crm_xml_add_int(cib_root, PCMK_XA_ADMIN_EPOCH, 0);
129
130 config = pcmk__xe_create(cib_root, PCMK_XE_CONFIGURATION);
131 pcmk__xe_create(cib_root, PCMK_XE_STATUS);
132
133 pcmk__xe_create(config, PCMK_XE_CRM_CONFIG);
134 pcmk__xe_create(config, PCMK_XE_NODES);
135 pcmk__xe_create(config, PCMK_XE_RESOURCES);
136 pcmk__xe_create(config, PCMK_XE_CONSTRAINTS);
137
138 #if PCMK__RESOURCE_STICKINESS_DEFAULT != 0
139 {
140 xmlNode *rsc_defaults = pcmk__xe_create(config, PCMK_XE_RSC_DEFAULTS);
141 xmlNode *meta = pcmk__xe_create(rsc_defaults, PCMK_XE_META_ATTRIBUTES);
142 xmlNode *nvpair = pcmk__xe_create(meta, PCMK_XE_NVPAIR);
143
144 crm_xml_add(meta, PCMK_XA_ID, "build-resource-defaults");
145 crm_xml_add(nvpair, PCMK_XA_ID, "build-" PCMK_META_RESOURCE_STICKINESS);
146 crm_xml_add(nvpair, PCMK_XA_NAME, PCMK_META_RESOURCE_STICKINESS);
147 crm_xml_add_int(nvpair, PCMK_XA_VALUE,
148 PCMK__RESOURCE_STICKINESS_DEFAULT);
149 }
150 #endif
151 return cib_root;
152 }
153
154 static bool
155 cib_acl_enabled(xmlNode *xml, const char *user)
156 {
157 bool rc = FALSE;
158
159 if(pcmk_acl_required(user)) {
160 const char *value = NULL;
161 GHashTable *options = pcmk__strkey_table(free, free);
162
163 cib_read_config(options, xml);
164 value = pcmk__cluster_option(options, PCMK_OPT_ENABLE_ACL);
165 rc = crm_is_true(value);
166 g_hash_table_destroy(options);
167 }
168
169 crm_trace("CIB ACL is %s", rc ? "enabled" : "disabled");
170 return rc;
171 }
172
173
174
175
176
177
178
179
180
181
182
183 static bool
184 should_copy_cib(const char *op, const char *section, int call_options)
185 {
186 if (pcmk_is_set(call_options, cib_dryrun)) {
187
188 return true;
189 }
190
191 if (pcmk__str_eq(op, PCMK__CIB_REQUEST_COMMIT_TRANSACT, pcmk__str_none)) {
192
193
194
195
196 return true;
197 }
198
199 if (pcmk_is_set(call_options, cib_transaction)) {
200
201
202
203
204 return false;
205 }
206
207 if (pcmk__str_eq(section, PCMK_XE_STATUS, pcmk__str_none)) {
208
209
210
211
212
213
214 return false;
215 }
216
217
218 return true;
219 }
220
221 int
222 cib_perform_op(cib_t *cib, const char *op, uint32_t call_options,
223 cib__op_fn_t fn, bool is_query, const char *section,
224 xmlNode *req, xmlNode *input, bool manage_counters,
225 bool *config_changed, xmlNode **current_cib,
226 xmlNode **result_cib, xmlNode **diff, xmlNode **output)
227 {
228 int rc = pcmk_ok;
229 bool check_schema = true;
230 bool make_copy = true;
231 xmlNode *top = NULL;
232 xmlNode *scratch = NULL;
233 xmlNode *patchset_cib = NULL;
234 xmlNode *local_diff = NULL;
235
236 const char *user = crm_element_value(req, PCMK__XA_CIB_USER);
237 bool with_digest = false;
238
239 crm_trace("Begin %s%s%s op",
240 (pcmk_is_set(call_options, cib_dryrun)? "dry run of " : ""),
241 (is_query? "read-only " : ""), op);
242
243 CRM_CHECK(output != NULL, return -ENOMSG);
244 CRM_CHECK(current_cib != NULL, return -ENOMSG);
245 CRM_CHECK(result_cib != NULL, return -ENOMSG);
246 CRM_CHECK(config_changed != NULL, return -ENOMSG);
247
248 if(output) {
249 *output = NULL;
250 }
251
252 *result_cib = NULL;
253 *config_changed = false;
254
255 if (fn == NULL) {
256 return -EINVAL;
257 }
258
259 if (is_query) {
260 xmlNode *cib_ro = *current_cib;
261 xmlNode *cib_filtered = NULL;
262
263 if (cib_acl_enabled(cib_ro, user)
264 && xml_acl_filtered_copy(user, *current_cib, *current_cib,
265 &cib_filtered)) {
266
267 if (cib_filtered == NULL) {
268 crm_debug("Pre-filtered the entire cib");
269 return -EACCES;
270 }
271 cib_ro = cib_filtered;
272 crm_log_xml_trace(cib_ro, "filtered");
273 }
274
275 rc = (*fn) (op, call_options, section, req, input, cib_ro, result_cib, output);
276
277 if(output == NULL || *output == NULL) {
278
279
280 } else if(cib_filtered == *output) {
281 cib_filtered = NULL;
282
283 } else if (*output == *current_cib) {
284
285
286 } else if(cib_filtered && (*output)->doc == cib_filtered->doc) {
287
288 *output = pcmk__xml_copy(NULL, *output);
289
290 } else if ((*output)->doc == (*current_cib)->doc) {
291
292 *output = pcmk__xml_copy(NULL, *output);
293 }
294
295 pcmk__xml_free(cib_filtered);
296 return rc;
297 }
298
299 make_copy = should_copy_cib(op, section, call_options);
300
301 if (!make_copy) {
302
303
304 scratch = *current_cib;
305
306
307 top = pcmk__xe_create(NULL, (const char *) scratch->name);
308 pcmk__xe_copy_attrs(top, scratch, pcmk__xaf_none);
309 patchset_cib = top;
310
311 xml_track_changes(scratch, user, NULL, cib_acl_enabled(scratch, user));
312 rc = (*fn) (op, call_options, section, req, input, scratch, &scratch, output);
313
314
315
316
317 *current_cib = scratch;
318
319 } else {
320 scratch = pcmk__xml_copy(NULL, *current_cib);
321 patchset_cib = *current_cib;
322
323 xml_track_changes(scratch, user, NULL, cib_acl_enabled(scratch, user));
324 rc = (*fn) (op, call_options, section, req, input, *current_cib,
325 &scratch, output);
326
327 if ((scratch != NULL) && !xml_tracking_changes(scratch)) {
328 crm_trace("Inferring changes after %s op", op);
329 xml_track_changes(scratch, user, *current_cib,
330 cib_acl_enabled(*current_cib, user));
331 xml_calculate_changes(*current_cib, scratch);
332 }
333 CRM_CHECK(*current_cib != scratch, return -EINVAL);
334 }
335
336 xml_acl_disable(scratch);
337
338 if (rc == pcmk_ok && scratch == NULL) {
339 rc = -EINVAL;
340 goto done;
341
342 } else if(rc == pcmk_ok && xml_acl_denied(scratch)) {
343 crm_trace("ACL rejected part or all of the proposed changes");
344 rc = -EACCES;
345 goto done;
346
347 } else if (rc != pcmk_ok) {
348 goto done;
349 }
350
351
352
353
354
355 if (scratch && (cib == NULL || cib->variant != cib_file)) {
356 const char *new_version = crm_element_value(scratch, PCMK_XA_CRM_FEATURE_SET);
357
358 rc = pcmk__check_feature_set(new_version);
359 if (rc != pcmk_rc_ok) {
360 crm_err("Discarding update with feature set '%s' greater than "
361 "our own '%s'", new_version, CRM_FEATURE_SET);
362 rc = pcmk_rc2legacy(rc);
363 goto done;
364 }
365 }
366
367 if (patchset_cib != NULL) {
368 int old = 0;
369 int new = 0;
370
371 crm_element_value_int(scratch, PCMK_XA_ADMIN_EPOCH, &new);
372 crm_element_value_int(patchset_cib, PCMK_XA_ADMIN_EPOCH, &old);
373
374 if (old > new) {
375 crm_err("%s went backwards: %d -> %d (Opts: %#x)",
376 PCMK_XA_ADMIN_EPOCH, old, new, call_options);
377 crm_log_xml_warn(req, "Bad Op");
378 crm_log_xml_warn(input, "Bad Data");
379 rc = -pcmk_err_old_data;
380
381 } else if (old == new) {
382 crm_element_value_int(scratch, PCMK_XA_EPOCH, &new);
383 crm_element_value_int(patchset_cib, PCMK_XA_EPOCH, &old);
384 if (old > new) {
385 crm_err("%s went backwards: %d -> %d (Opts: %#x)",
386 PCMK_XA_EPOCH, old, new, call_options);
387 crm_log_xml_warn(req, "Bad Op");
388 crm_log_xml_warn(input, "Bad Data");
389 rc = -pcmk_err_old_data;
390 }
391 }
392 }
393
394 crm_trace("Massaging CIB contents");
395 pcmk__strip_xml_text(scratch);
396
397 if (make_copy) {
398 static time_t expires = 0;
399 time_t tm_now = time(NULL);
400
401 if (expires < tm_now) {
402 expires = tm_now + 60;
403 with_digest = true;
404 }
405 }
406
407 local_diff = xml_create_patchset(0, patchset_cib, scratch,
408 config_changed, manage_counters);
409
410 pcmk__log_xml_changes(LOG_TRACE, scratch);
411 xml_accept_changes(scratch);
412
413 if(local_diff) {
414 patchset_process_digest(local_diff, patchset_cib, scratch, with_digest);
415 pcmk__log_xml_patchset(LOG_INFO, local_diff);
416 crm_log_xml_trace(local_diff, "raw patch");
417 }
418
419 if (make_copy && (local_diff != NULL)) {
420
421 pcmk__if_tracing(
422 {
423
424 int test_rc = pcmk_ok;
425 int format = 1;
426 xmlNode *cib_copy = pcmk__xml_copy(NULL, patchset_cib);
427
428 crm_element_value_int(local_diff, PCMK_XA_FORMAT, &format);
429 test_rc = xml_apply_patchset(cib_copy, local_diff,
430 manage_counters);
431
432 if (test_rc != pcmk_ok) {
433 save_xml_to_file(cib_copy, "PatchApply:calculated", NULL);
434 save_xml_to_file(patchset_cib, "PatchApply:input", NULL);
435 save_xml_to_file(scratch, "PatchApply:actual", NULL);
436 save_xml_to_file(local_diff, "PatchApply:diff", NULL);
437 crm_err("v%d patchset error, patch failed to apply: %s "
438 "(%d)",
439 format, pcmk_rc_str(pcmk_legacy2rc(test_rc)),
440 test_rc);
441 }
442 pcmk__xml_free(cib_copy);
443 },
444 {}
445 );
446 }
447
448 if (pcmk__str_eq(section, PCMK_XE_STATUS, pcmk__str_casei)) {
449
450
451
452
453 check_schema = false;
454 }
455
456
457
458
459
460
461
462
463
464
465
466
467
468 if (*config_changed && !pcmk_is_set(call_options, cib_no_mtime)) {
469 const char *schema = crm_element_value(scratch, PCMK_XA_VALIDATE_WITH);
470
471 if (schema == NULL) {
472 rc = -pcmk_err_cib_corrupt;
473 }
474
475 pcmk__xe_add_last_written(scratch);
476 pcmk__warn_if_schema_deprecated(schema);
477
478
479
480
481 if (pcmk__cmp_schemas_by_name(schema, "pacemaker-1.2") >= 0) {
482 const char *origin = crm_element_value(req, PCMK__XA_SRC);
483 const char *client = crm_element_value(req,
484 PCMK__XA_CIB_CLIENTNAME);
485
486 if (origin != NULL) {
487 crm_xml_add(scratch, PCMK_XA_UPDATE_ORIGIN, origin);
488 } else {
489 pcmk__xe_remove_attr(scratch, PCMK_XA_UPDATE_ORIGIN);
490 }
491
492 if (client != NULL) {
493 crm_xml_add(scratch, PCMK_XA_UPDATE_CLIENT, user);
494 } else {
495 pcmk__xe_remove_attr(scratch, PCMK_XA_UPDATE_CLIENT);
496 }
497
498 if (user != NULL) {
499 crm_xml_add(scratch, PCMK_XA_UPDATE_USER, user);
500 } else {
501 pcmk__xe_remove_attr(scratch, PCMK_XA_UPDATE_USER);
502 }
503 }
504 }
505
506 crm_trace("Perform validation: %s", pcmk__btoa(check_schema));
507 if ((rc == pcmk_ok) && check_schema
508 && !pcmk__configured_schema_validates(scratch)) {
509 rc = -pcmk_err_schema_validation;
510 }
511
512 done:
513
514 *result_cib = scratch;
515
516
517
518
519 if ((rc != pcmk_ok) && cib_acl_enabled(patchset_cib, user)
520 && xml_acl_filtered_copy(user, patchset_cib, scratch, result_cib)) {
521
522 if (*result_cib == NULL) {
523 crm_debug("Pre-filtered the entire cib result");
524 }
525 pcmk__xml_free(scratch);
526 }
527
528 if(diff) {
529 *diff = local_diff;
530 } else {
531 pcmk__xml_free(local_diff);
532 }
533
534 pcmk__xml_free(top);
535 crm_trace("Done");
536 return rc;
537 }
538
539 int
540 cib__create_op(cib_t *cib, const char *op, const char *host,
541 const char *section, xmlNode *data, int call_options,
542 const char *user_name, const char *client_name,
543 xmlNode **op_msg)
544 {
545 CRM_CHECK((cib != NULL) && (op_msg != NULL), return -EPROTO);
546
547 *op_msg = pcmk__xe_create(NULL, PCMK__XE_CIB_COMMAND);
548
549 cib->call_id++;
550 if (cib->call_id < 1) {
551 cib->call_id = 1;
552 }
553
554 crm_xml_add(*op_msg, PCMK__XA_T, PCMK__VALUE_CIB);
555 crm_xml_add(*op_msg, PCMK__XA_CIB_OP, op);
556 crm_xml_add(*op_msg, PCMK__XA_CIB_HOST, host);
557 crm_xml_add(*op_msg, PCMK__XA_CIB_SECTION, section);
558 crm_xml_add(*op_msg, PCMK__XA_CIB_USER, user_name);
559 crm_xml_add(*op_msg, PCMK__XA_CIB_CLIENTNAME, client_name);
560 crm_xml_add_int(*op_msg, PCMK__XA_CIB_CALLID, cib->call_id);
561
562 crm_trace("Sending call options: %.8lx, %d", (long)call_options, call_options);
563 crm_xml_add_int(*op_msg, PCMK__XA_CIB_CALLOPT, call_options);
564
565 if (data != NULL) {
566 xmlNode *wrapper = pcmk__xe_create(*op_msg, PCMK__XE_CIB_CALLDATA);
567
568 pcmk__xml_copy(wrapper, data);
569 }
570
571 return pcmk_ok;
572 }
573
574
575
576
577
578
579
580
581
582 static int
583 validate_transaction_request(const xmlNode *request)
584 {
585 const char *op = crm_element_value(request, PCMK__XA_CIB_OP);
586 const char *host = crm_element_value(request, PCMK__XA_CIB_HOST);
587 const cib__operation_t *operation = NULL;
588 int rc = cib__get_operation(op, &operation);
589
590 if (rc != pcmk_rc_ok) {
591
592 return rc;
593 }
594
595 if (!pcmk_is_set(operation->flags, cib__op_attr_transaction)) {
596 crm_err("Operation %s is not supported in CIB transactions", op);
597 return EOPNOTSUPP;
598 }
599
600 if (host != NULL) {
601 crm_err("Operation targeting a specific node (%s) is not supported in "
602 "a CIB transaction",
603 host);
604 return EOPNOTSUPP;
605 }
606 return pcmk_rc_ok;
607 }
608
609
610
611
612
613
614
615
616
617
618 int
619 cib__extend_transaction(cib_t *cib, xmlNode *request)
620 {
621 int rc = pcmk_rc_ok;
622
623 pcmk__assert((cib != NULL) && (request != NULL));
624
625 rc = validate_transaction_request(request);
626
627 if ((rc == pcmk_rc_ok) && (cib->transaction == NULL)) {
628 rc = pcmk_rc_no_transaction;
629 }
630
631 if (rc == pcmk_rc_ok) {
632 pcmk__xml_copy(cib->transaction, request);
633
634 } else {
635 const char *op = crm_element_value(request, PCMK__XA_CIB_OP);
636 const char *client_id = NULL;
637
638 cib->cmds->client_id(cib, NULL, &client_id);
639 crm_err("Failed to add '%s' operation to transaction for client %s: %s",
640 op, pcmk__s(client_id, "(unidentified)"), pcmk_rc_str(rc));
641 crm_log_xml_info(request, "failed");
642 }
643 return pcmk_rc2legacy(rc);
644 }
645
646 void
647 cib_native_callback(cib_t * cib, xmlNode * msg, int call_id, int rc)
648 {
649 xmlNode *output = NULL;
650 cib_callback_client_t *blob = NULL;
651
652 if (msg != NULL) {
653 xmlNode *wrapper = NULL;
654
655 crm_element_value_int(msg, PCMK__XA_CIB_RC, &rc);
656 crm_element_value_int(msg, PCMK__XA_CIB_CALLID, &call_id);
657 wrapper = pcmk__xe_first_child(msg, PCMK__XE_CIB_CALLDATA, NULL, NULL);
658 output = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
659 }
660
661 blob = cib__lookup_id(call_id);
662
663 if (blob == NULL) {
664 crm_trace("No callback found for call %d", call_id);
665 }
666
667 if (cib == NULL) {
668 crm_debug("No cib object supplied");
669 }
670
671 if (rc == -pcmk_err_diff_resync) {
672
673 rc = pcmk_ok;
674 }
675
676 if (blob && blob->callback && (rc == pcmk_ok || blob->only_success == FALSE)) {
677 crm_trace("Invoking callback %s for call %d",
678 pcmk__s(blob->id, "without ID"), call_id);
679 blob->callback(msg, call_id, rc, output, blob->user_data);
680
681 } else if ((cib != NULL) && (rc != pcmk_ok)) {
682 crm_warn("CIB command failed: %s", pcmk_strerror(rc));
683 crm_log_xml_debug(msg, "Failed CIB Update");
684 }
685
686
687 if (blob) {
688 remove_cib_op_callback(call_id, FALSE);
689 }
690
691 crm_trace("OP callback activated for %d", call_id);
692 }
693
694 void
695 cib_native_notify(gpointer data, gpointer user_data)
696 {
697 xmlNode *msg = user_data;
698 cib_notify_client_t *entry = data;
699 const char *event = NULL;
700
701 if (msg == NULL) {
702 crm_warn("Skipping callback - NULL message");
703 return;
704 }
705
706 event = crm_element_value(msg, PCMK__XA_SUBT);
707
708 if (entry == NULL) {
709 crm_warn("Skipping callback - NULL callback client");
710 return;
711
712 } else if (entry->callback == NULL) {
713 crm_warn("Skipping callback - NULL callback");
714 return;
715
716 } else if (!pcmk__str_eq(entry->event, event, pcmk__str_casei)) {
717 crm_trace("Skipping callback - event mismatch %p/%s vs. %s", entry, entry->event, event);
718 return;
719 }
720
721 crm_trace("Invoking callback for %p/%s event...", entry, event);
722 entry->callback(event, msg);
723 crm_trace("Callback invoked...");
724 }
725
726 gboolean
727 cib_read_config(GHashTable * options, xmlNode * current_cib)
728 {
729 xmlNode *config = NULL;
730 crm_time_t *now = NULL;
731
732 if (options == NULL || current_cib == NULL) {
733 return FALSE;
734 }
735
736 now = crm_time_new(NULL);
737
738 g_hash_table_remove_all(options);
739
740 config = pcmk_find_cib_element(current_cib, PCMK_XE_CRM_CONFIG);
741 if (config) {
742 pe_unpack_nvpairs(NULL, config, PCMK_XE_CLUSTER_PROPERTY_SET, NULL,
743 options, PCMK_VALUE_CIB_BOOTSTRAP_OPTIONS, FALSE, now,
744 NULL);
745 }
746
747 pcmk__validate_cluster_options(options);
748
749 crm_time_free(now);
750
751 return TRUE;
752 }
753
754 int
755 cib_internal_op(cib_t * cib, const char *op, const char *host,
756 const char *section, xmlNode * data,
757 xmlNode ** output_data, int call_options, const char *user_name)
758 {
759 int (*delegate)(cib_t *cib, const char *op, const char *host,
760 const char *section, xmlNode *data, xmlNode **output_data,
761 int call_options, const char *user_name) = NULL;
762
763 if (cib == NULL) {
764 return -EINVAL;
765 }
766
767 delegate = cib->delegate_fn;
768 if (delegate == NULL) {
769 return -EPROTONOSUPPORT;
770 }
771 if (user_name == NULL) {
772 user_name = getenv("CIB_user");
773 }
774 return delegate(cib, op, host, section, data, output_data, call_options, user_name);
775 }
776
777
778
779
780
781
782
783
784
785
786
787
788 int
789 cib_apply_patch_event(xmlNode *event, xmlNode *input, xmlNode **output,
790 int level)
791 {
792 int rc = pcmk_err_generic;
793
794 xmlNode *wrapper = NULL;
795 xmlNode *diff = NULL;
796
797 pcmk__assert((event != NULL) && (input != NULL) && (output != NULL));
798
799 crm_element_value_int(event, PCMK__XA_CIB_RC, &rc);
800 wrapper = pcmk__xe_first_child(event, PCMK__XE_CIB_UPDATE_RESULT, NULL,
801 NULL);
802 diff = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
803
804 if (rc < pcmk_ok || diff == NULL) {
805 return rc;
806 }
807
808 if (level > LOG_CRIT) {
809 pcmk__log_xml_patchset(level, diff);
810 }
811
812 if (input != NULL) {
813 rc = cib_process_diff(NULL, cib_none, NULL, event, diff, input, output,
814 NULL);
815
816 if (rc != pcmk_ok) {
817 crm_debug("Update didn't apply: %s (%d) %p",
818 pcmk_strerror(rc), rc, *output);
819
820 if (rc == -pcmk_err_old_data) {
821 crm_trace("Masking error, we already have the supplied update");
822 return pcmk_ok;
823 }
824 pcmk__xml_free(*output);
825 *output = NULL;
826 return rc;
827 }
828 }
829 return rc;
830 }
831
832 #define log_signon_query_err(out, fmt, args...) do { \
833 if (out != NULL) { \
834 out->err(out, fmt, ##args); \
835 } else { \
836 crm_err(fmt, ##args); \
837 } \
838 } while (0)
839
840 int
841 cib__signon_query(pcmk__output_t *out, cib_t **cib, xmlNode **cib_object)
842 {
843 int rc = pcmk_rc_ok;
844 cib_t *cib_conn = NULL;
845
846 pcmk__assert(cib_object != NULL);
847
848 if (cib == NULL) {
849 cib_conn = cib_new();
850 } else {
851 if (*cib == NULL) {
852 *cib = cib_new();
853 }
854 cib_conn = *cib;
855 }
856
857 if (cib_conn == NULL) {
858 return ENOMEM;
859 }
860
861 if (cib_conn->state == cib_disconnected) {
862 rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command);
863 rc = pcmk_legacy2rc(rc);
864 }
865
866 if (rc != pcmk_rc_ok) {
867 log_signon_query_err(out, "Could not connect to the CIB: %s",
868 pcmk_rc_str(rc));
869 goto done;
870 }
871
872 if (out != NULL) {
873 out->transient(out, "Querying CIB...");
874 }
875 rc = cib_conn->cmds->query(cib_conn, NULL, cib_object, cib_sync_call);
876 rc = pcmk_legacy2rc(rc);
877
878 if (rc != pcmk_rc_ok) {
879 log_signon_query_err(out, "CIB query failed: %s", pcmk_rc_str(rc));
880 }
881
882 done:
883 if (cib == NULL) {
884 cib__clean_up_connection(&cib_conn);
885 }
886
887 if ((rc == pcmk_rc_ok) && (*cib_object == NULL)) {
888 return pcmk_rc_no_input;
889 }
890 return rc;
891 }
892
893 int
894 cib__signon_attempts(cib_t *cib, enum cib_conn_type type, int attempts)
895 {
896 int rc = pcmk_rc_ok;
897
898 crm_trace("Attempting connection to CIB manager (up to %d time%s)",
899 attempts, pcmk__plural_s(attempts));
900
901 for (int remaining = attempts - 1; remaining >= 0; --remaining) {
902 rc = cib->cmds->signon(cib, crm_system_name, type);
903
904 if ((rc == pcmk_rc_ok)
905 || (remaining == 0)
906 || ((errno != EAGAIN) && (errno != EALREADY))) {
907 break;
908 }
909
910
911 pcmk__sleep_ms((attempts - remaining) * 500);
912 crm_debug("Re-attempting connection to CIB manager (%d attempt%s remaining)",
913 remaining, pcmk__plural_s(remaining));
914 }
915
916 return rc;
917 }
918
919 int
920 cib__clean_up_connection(cib_t **cib)
921 {
922 int rc;
923
924 if (*cib == NULL) {
925 return pcmk_rc_ok;
926 }
927
928 rc = (*cib)->cmds->signoff(*cib);
929 cib_delete(*cib);
930 *cib = NULL;
931 return pcmk_legacy2rc(rc);
932 }