This source file includes following definitions.
- handle_cib_disconnect
- do_cib_updated
- controld_disconnect_cib_manager
- do_cib_control
- cib_op_timeout
- crmd_cib_smart_opt
- cib_delete_callback
- controld_node_state_deletion_strings
- controld_delete_node_state
- controld_delete_resource_history
- build_parameter_list
- append_restart_list
- append_secure_list
- controld_add_resource_history_xml_as
- controld_record_pending_op
- cib_rsc_callback
- should_preserve_lock
- controld_update_cib
- controld_update_resource_history
- controld_delete_action_history
- controld_cib_delete_last_failure
- controld_delete_action_history_by_key
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <unistd.h>
13
14 #include <crm/common/alerts_internal.h>
15 #include <crm/common/xml.h>
16 #include <crm/crm.h>
17 #include <crm/lrmd_internal.h>
18
19 #include <pacemaker-controld.h>
20
21
22 static int pending_rsc_update = 0;
23
24
25
26
27
28
29
30 static void
31 handle_cib_disconnect(gpointer user_data)
32 {
33 CRM_LOG_ASSERT(user_data == controld_globals.cib_conn);
34
35 controld_trigger_fsa();
36 controld_globals.cib_conn->state = cib_disconnected;
37
38 if (pcmk_is_set(controld_globals.fsa_input_register, R_CIB_CONNECTED)) {
39
40 crm_crit("Lost connection to the CIB manager, shutting down");
41 register_fsa_input(C_FSA_INTERNAL, I_ERROR, NULL);
42 controld_clear_fsa_input_flags(R_CIB_CONNECTED);
43
44 } else {
45 crm_info("Disconnected from the CIB manager");
46 }
47 }
48
49 static void
50 do_cib_updated(const char *event, xmlNode * msg)
51 {
52 const xmlNode *patchset = NULL;
53 const char *client_name = NULL;
54
55 crm_debug("Received CIB diff notification: DC=%s", pcmk__btoa(AM_I_DC));
56
57 if (cib__get_notify_patchset(msg, &patchset) != pcmk_rc_ok) {
58 return;
59 }
60
61 if (cib__element_in_patchset(patchset, PCMK_XE_ALERTS)
62 || cib__element_in_patchset(patchset, PCMK_XE_CRM_CONFIG)) {
63
64 controld_trigger_config();
65 }
66
67 if (!AM_I_DC) {
68
69 return;
70 }
71
72 client_name = crm_element_value(msg, PCMK__XA_CIB_CLIENTNAME);
73 if (!cib__client_triggers_refresh(client_name)) {
74
75 return;
76 }
77
78 if (cib__element_in_patchset(patchset, PCMK_XE_NODES)
79 || cib__element_in_patchset(patchset, PCMK_XE_STATUS)) {
80
81
82
83
84
85 if (client_name == NULL) {
86 client_name = crm_element_value(msg, PCMK__XA_CIB_CLIENTID);
87 }
88 crm_notice("Populating nodes and starting an election after %s event "
89 "triggered by %s",
90 event, pcmk__s(client_name, "(unidentified client)"));
91
92 populate_cib_nodes(node_update_quick|node_update_all, __func__);
93 register_fsa_input(C_FSA_INTERNAL, I_ELECTION, NULL);
94 }
95 }
96
97 void
98 controld_disconnect_cib_manager(void)
99 {
100 cib_t *cib_conn = controld_globals.cib_conn;
101
102 CRM_ASSERT(cib_conn != NULL);
103
104 crm_debug("Disconnecting from the CIB manager");
105
106 controld_clear_fsa_input_flags(R_CIB_CONNECTED);
107
108 cib_conn->cmds->del_notify_callback(cib_conn, PCMK__VALUE_CIB_DIFF_NOTIFY,
109 do_cib_updated);
110 cib_free_callbacks(cib_conn);
111
112 if (cib_conn->state != cib_disconnected) {
113 cib_conn->cmds->set_secondary(cib_conn,
114 cib_scope_local|cib_discard_reply);
115 cib_conn->cmds->signoff(cib_conn);
116 }
117 }
118
119
120 void
121 do_cib_control(long long action,
122 enum crmd_fsa_cause cause,
123 enum crmd_fsa_state cur_state,
124 enum crmd_fsa_input current_input, fsa_data_t * msg_data)
125 {
126 static int cib_retries = 0;
127
128 cib_t *cib_conn = controld_globals.cib_conn;
129
130 void (*dnotify_fn) (gpointer user_data) = handle_cib_disconnect;
131 void (*update_cb) (const char *event, xmlNodePtr msg) = do_cib_updated;
132
133 int rc = pcmk_ok;
134
135 CRM_ASSERT(cib_conn != NULL);
136
137 if (pcmk_is_set(action, A_CIB_STOP)) {
138 if ((cib_conn->state != cib_disconnected)
139 && (pending_rsc_update != 0)) {
140
141 crm_info("Waiting for resource update %d to complete",
142 pending_rsc_update);
143 crmd_fsa_stall(FALSE);
144 return;
145 }
146 controld_disconnect_cib_manager();
147 }
148
149 if (!pcmk_is_set(action, A_CIB_START)) {
150 return;
151 }
152
153 if (cur_state == S_STOPPING) {
154 crm_err("Ignoring request to connect to the CIB manager after "
155 "shutdown");
156 return;
157 }
158
159 rc = cib_conn->cmds->signon(cib_conn, CRM_SYSTEM_CRMD,
160 cib_command_nonblocking);
161
162 if (rc != pcmk_ok) {
163
164 sleep(1);
165 rc = cib_conn->cmds->signon(cib_conn, CRM_SYSTEM_CRMD,
166 cib_command_nonblocking);
167 }
168
169 if (rc != pcmk_ok) {
170 crm_info("Could not connect to the CIB manager: %s", pcmk_strerror(rc));
171
172 } else if (cib_conn->cmds->set_connection_dnotify(cib_conn,
173 dnotify_fn) != pcmk_ok) {
174 crm_err("Could not set dnotify callback");
175
176 } else if (cib_conn->cmds->add_notify_callback(cib_conn,
177 PCMK__VALUE_CIB_DIFF_NOTIFY,
178 update_cb) != pcmk_ok) {
179 crm_err("Could not set CIB notification callback (update)");
180
181 } else {
182 controld_set_fsa_input_flags(R_CIB_CONNECTED);
183 cib_retries = 0;
184 }
185
186 if (!pcmk_is_set(controld_globals.fsa_input_register, R_CIB_CONNECTED)) {
187 cib_retries++;
188
189 if (cib_retries < 30) {
190 crm_warn("Couldn't complete CIB registration %d times... "
191 "pause and retry", cib_retries);
192 controld_start_wait_timer();
193 crmd_fsa_stall(FALSE);
194
195 } else {
196 crm_err("Could not complete CIB registration %d times... "
197 "hard error", cib_retries);
198 register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
199 }
200 }
201 }
202
203 #define MIN_CIB_OP_TIMEOUT (30)
204
205
206
207
208
209
210
211
212
213 unsigned int
214 cib_op_timeout(void)
215 {
216
217 static int env_timeout = -1;
218 unsigned int calculated_timeout = 0;
219
220 if (env_timeout == -1) {
221 const char *env = pcmk__env_option(PCMK__ENV_CIB_TIMEOUT);
222
223 pcmk__scan_min_int(env, &env_timeout, MIN_CIB_OP_TIMEOUT);
224 crm_trace("Minimum CIB op timeout: %ds (environment: %s)",
225 env_timeout, (env? env : "none"));
226 }
227
228 calculated_timeout = 10U * (1U
229 + pcmk__cluster_num_active_nodes()
230 + pcmk__cluster_num_remote_nodes());
231 calculated_timeout = QB_MAX(calculated_timeout, env_timeout);
232 crm_trace("Calculated timeout: %us", calculated_timeout);
233
234 if (controld_globals.cib_conn) {
235 controld_globals.cib_conn->call_timeout = calculated_timeout;
236 }
237 return calculated_timeout;
238 }
239
240
241
242
243
244
245
246 int
247 crmd_cib_smart_opt(void)
248 {
249 int call_opt = cib_none;
250
251 if ((controld_globals.fsa_state == S_ELECTION)
252 || (controld_globals.fsa_state == S_PENDING)) {
253 crm_info("Sending update to local CIB in state: %s",
254 fsa_state2string(controld_globals.fsa_state));
255 cib__set_call_options(call_opt, "update", cib_scope_local);
256 }
257 return call_opt;
258 }
259
260 static void
261 cib_delete_callback(xmlNode *msg, int call_id, int rc, xmlNode *output,
262 void *user_data)
263 {
264 char *desc = user_data;
265
266 if (rc == 0) {
267 crm_debug("Deletion of %s (via CIB call %d) succeeded", desc, call_id);
268 } else {
269 crm_warn("Deletion of %s (via CIB call %d) failed: %s " CRM_XS " rc=%d",
270 desc, call_id, pcmk_strerror(rc), rc);
271 }
272 }
273
274
275
276
277 #define XPATH_NODE_STATE "//" PCMK__XE_NODE_STATE "[@" PCMK_XA_UNAME "='%s']"
278
279
280 #define XPATH_NODE_LRM XPATH_NODE_STATE "/" PCMK__XE_LRM
281
282
283
284
285
286 #define XPATH_NODE_LRM_UNLOCKED XPATH_NODE_STATE "//" PCMK__XE_LRM_RSC_OP \
287 "|" XPATH_NODE_STATE \
288 "//" PCMK__XE_LRM_RESOURCE \
289 "[not(@" PCMK_OPT_SHUTDOWN_LOCK ") " \
290 "or " PCMK_OPT_SHUTDOWN_LOCK "<%lld]"
291
292
293 #define XPATH_NODE_ATTRS XPATH_NODE_STATE "/" PCMK__XE_TRANSIENT_ATTRIBUTES
294
295
296 #define XPATH_NODE_ALL XPATH_NODE_STATE "/*"
297
298
299
300
301 #define XPATH_NODE_ALL_UNLOCKED XPATH_NODE_LRM_UNLOCKED "|" XPATH_NODE_ATTRS
302
303
304
305
306
307
308
309
310
311
312 void
313 controld_node_state_deletion_strings(const char *uname,
314 enum controld_section_e section,
315 char **xpath, char **desc)
316 {
317 const char *desc_pre = NULL;
318
319
320 long long expire = (long long) time(NULL)
321 - controld_globals.shutdown_lock_limit;
322
323 switch (section) {
324 case controld_section_lrm:
325 *xpath = crm_strdup_printf(XPATH_NODE_LRM, uname);
326 desc_pre = "resource history";
327 break;
328 case controld_section_lrm_unlocked:
329 *xpath = crm_strdup_printf(XPATH_NODE_LRM_UNLOCKED,
330 uname, uname, expire);
331 desc_pre = "resource history (other than shutdown locks)";
332 break;
333 case controld_section_attrs:
334 *xpath = crm_strdup_printf(XPATH_NODE_ATTRS, uname);
335 desc_pre = "transient attributes";
336 break;
337 case controld_section_all:
338 *xpath = crm_strdup_printf(XPATH_NODE_ALL, uname);
339 desc_pre = "all state";
340 break;
341 case controld_section_all_unlocked:
342 *xpath = crm_strdup_printf(XPATH_NODE_ALL_UNLOCKED,
343 uname, uname, expire, uname);
344 desc_pre = "all state (other than shutdown locks)";
345 break;
346 default:
347
348 CRM_ASSERT(false);
349 break;
350 }
351
352 if (desc != NULL) {
353 *desc = crm_strdup_printf("%s for node %s", desc_pre, uname);
354 }
355 }
356
357
358
359
360
361
362
363
364
365 void
366 controld_delete_node_state(const char *uname, enum controld_section_e section,
367 int options)
368 {
369 cib_t *cib = controld_globals.cib_conn;
370 char *xpath = NULL;
371 char *desc = NULL;
372 int cib_rc = pcmk_ok;
373
374 CRM_ASSERT((uname != NULL) && (cib != NULL));
375
376 controld_node_state_deletion_strings(uname, section, &xpath, &desc);
377
378 cib__set_call_options(options, "node state deletion",
379 cib_xpath|cib_multiple);
380 cib_rc = cib->cmds->remove(cib, xpath, NULL, options);
381 fsa_register_cib_callback(cib_rc, desc, cib_delete_callback);
382 crm_info("Deleting %s (via CIB call %d) " CRM_XS " xpath=%s",
383 desc, cib_rc, xpath);
384
385
386 free(xpath);
387 }
388
389
390 #define XPATH_RESOURCE_HISTORY "//" PCMK__XE_NODE_STATE \
391 "[@" PCMK_XA_UNAME "='%s']/" \
392 PCMK__XE_LRM "/" PCMK__XE_LRM_RESOURCES \
393 "/" PCMK__XE_LRM_RESOURCE \
394 "[@" PCMK_XA_ID "='%s']"
395
396
397
398
399
400
401
402
403
404
405
406
407
408 int
409 controld_delete_resource_history(const char *rsc_id, const char *node,
410 const char *user_name, int call_options)
411 {
412 char *desc = NULL;
413 char *xpath = NULL;
414 int rc = pcmk_rc_ok;
415 cib_t *cib = controld_globals.cib_conn;
416
417 CRM_CHECK((rsc_id != NULL) && (node != NULL), return EINVAL);
418
419 desc = crm_strdup_printf("resource history for %s on %s", rsc_id, node);
420 if (cib == NULL) {
421 crm_err("Unable to clear %s: no CIB connection", desc);
422 free(desc);
423 return ENOTCONN;
424 }
425
426
427 xpath = crm_strdup_printf(XPATH_RESOURCE_HISTORY, node, rsc_id);
428
429 cib->cmds->set_user(cib, user_name);
430 rc = cib->cmds->remove(cib, xpath, NULL, call_options|cib_xpath);
431 cib->cmds->set_user(cib, NULL);
432
433 if (rc < 0) {
434 rc = pcmk_legacy2rc(rc);
435 crm_err("Could not delete resource status of %s on %s%s%s: %s "
436 CRM_XS " rc=%d", rsc_id, node,
437 (user_name? " for user " : ""), (user_name? user_name : ""),
438 pcmk_rc_str(rc), rc);
439 free(desc);
440 free(xpath);
441 return rc;
442 }
443
444 if (pcmk_is_set(call_options, cib_sync_call)) {
445 if (pcmk_is_set(call_options, cib_dryrun)) {
446 crm_debug("Deletion of %s would succeed", desc);
447 } else {
448 crm_debug("Deletion of %s succeeded", desc);
449 }
450 free(desc);
451
452 } else {
453 crm_info("Clearing %s (via CIB call %d) " CRM_XS " xpath=%s",
454 desc, rc, xpath);
455 fsa_register_cib_callback(rc, desc, cib_delete_callback);
456
457 }
458
459 free(xpath);
460 return pcmk_rc_ok;
461 }
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482 static GString *
483 build_parameter_list(const lrmd_event_data_t *op,
484 const struct ra_metadata_s *metadata,
485 enum ra_param_flags_e param_type, xmlNode **result)
486 {
487 GString *list = NULL;
488
489 *result = pcmk__xe_create(NULL, PCMK_XE_PARAMETERS);
490
491
492
493
494 if (param_type == ra_param_private
495 && compare_version(controld_globals.dc_version, "3.16.0") >= 0) {
496 g_hash_table_foreach(op->params, hash2field, *result);
497 pcmk__filter_op_for_digest(*result);
498 }
499
500 for (GList *iter = metadata->ra_params; iter != NULL; iter = iter->next) {
501 struct ra_param_s *param = (struct ra_param_s *) iter->data;
502
503 bool accept_for_list = false;
504 bool accept_for_xml = false;
505
506 switch (param_type) {
507 case ra_param_reloadable:
508 accept_for_list = !pcmk_is_set(param->rap_flags, param_type);
509 accept_for_xml = accept_for_list;
510 break;
511
512 case ra_param_unique:
513 accept_for_list = pcmk_is_set(param->rap_flags, param_type);
514 accept_for_xml = accept_for_list;
515 break;
516
517 case ra_param_private:
518 accept_for_list = pcmk_is_set(param->rap_flags, param_type);
519 accept_for_xml = !accept_for_list;
520 break;
521 }
522
523 if (accept_for_list) {
524 crm_trace("Attr %s is %s", param->rap_name, ra_param_flag2text(param_type));
525
526 if (list == NULL) {
527
528 pcmk__add_word(&list, 256, " ");
529 }
530 pcmk__add_word(&list, 0, param->rap_name);
531
532 } else {
533 crm_trace("Rejecting %s for %s", param->rap_name, ra_param_flag2text(param_type));
534 }
535
536 if (accept_for_xml) {
537 const char *v = g_hash_table_lookup(op->params, param->rap_name);
538
539 if (v != NULL) {
540 crm_trace("Adding attr %s=%s to the xml result", param->rap_name, v);
541 crm_xml_add(*result, param->rap_name, v);
542 }
543
544 } else {
545 crm_trace("Removing attr %s from the xml result", param->rap_name);
546 pcmk__xe_remove_attr(*result, param->rap_name);
547 }
548 }
549
550 if (list != NULL) {
551
552 pcmk__add_word(&list, 0, " ");
553 }
554 return list;
555 }
556
557 static void
558 append_restart_list(lrmd_event_data_t *op, struct ra_metadata_s *metadata,
559 xmlNode *update, const char *version)
560 {
561 GString *list = NULL;
562 char *digest = NULL;
563 xmlNode *restart = NULL;
564
565 CRM_LOG_ASSERT(op->params != NULL);
566
567 if (op->interval_ms > 0) {
568
569 return;
570 }
571
572 if (pcmk_is_set(metadata->ra_flags, ra_supports_reload_agent)) {
573
574
575
576 list = build_parameter_list(op, metadata, ra_param_reloadable,
577 &restart);
578
579 } else if (pcmk_is_set(metadata->ra_flags, ra_supports_legacy_reload)) {
580
581
582
583
584
585
586 list = build_parameter_list(op, metadata, ra_param_unique, &restart);
587
588 } else {
589
590 return;
591 }
592
593 digest = calculate_operation_digest(restart, version);
594
595
596
597
598 crm_xml_add(update, PCMK__XA_OP_FORCE_RESTART,
599 (list == NULL)? "" : (const char *) list->str);
600 crm_xml_add(update, PCMK__XA_OP_RESTART_DIGEST, digest);
601
602 if ((list != NULL) && (list->len > 0)) {
603 crm_trace("%s: %s, %s", op->rsc_id, digest, (const char *) list->str);
604 } else {
605 crm_trace("%s: %s", op->rsc_id, digest);
606 }
607
608 if (list != NULL) {
609 g_string_free(list, TRUE);
610 }
611 free_xml(restart);
612 free(digest);
613 }
614
615 static void
616 append_secure_list(lrmd_event_data_t *op, struct ra_metadata_s *metadata,
617 xmlNode *update, const char *version)
618 {
619 GString *list = NULL;
620 char *digest = NULL;
621 xmlNode *secure = NULL;
622
623 CRM_LOG_ASSERT(op->params != NULL);
624
625
626
627
628 list = build_parameter_list(op, metadata, ra_param_private, &secure);
629
630 if (list != NULL) {
631 digest = calculate_operation_digest(secure, version);
632 crm_xml_add(update, PCMK__XA_OP_SECURE_PARAMS,
633 (const char *) list->str);
634 crm_xml_add(update, PCMK__XA_OP_SECURE_DIGEST, digest);
635
636 crm_trace("%s: %s, %s", op->rsc_id, digest, (const char *) list->str);
637 g_string_free(list, TRUE);
638 } else {
639 crm_trace("%s: no secure parameters", op->rsc_id);
640 }
641
642 free_xml(secure);
643 free(digest);
644 }
645
646
647
648
649
650
651
652
653
654
655
656 void
657 controld_add_resource_history_xml_as(const char *func, xmlNode *parent,
658 const lrmd_rsc_info_t *rsc,
659 lrmd_event_data_t *op,
660 const char *node_name)
661 {
662 int target_rc = 0;
663 xmlNode *xml_op = NULL;
664 struct ra_metadata_s *metadata = NULL;
665 const char *caller_version = NULL;
666 lrm_state_t *lrm_state = NULL;
667
668 if (op == NULL) {
669 return;
670 }
671
672 target_rc = rsc_op_expected_rc(op);
673
674 caller_version = g_hash_table_lookup(op->params, PCMK_XA_CRM_FEATURE_SET);
675 CRM_CHECK(caller_version != NULL, caller_version = CRM_FEATURE_SET);
676
677 xml_op = pcmk__create_history_xml(parent, op, caller_version, target_rc,
678 controld_globals.our_nodename, func);
679 if (xml_op == NULL) {
680 return;
681 }
682
683 if ((rsc == NULL) || (op->params == NULL)
684 || !crm_op_needs_metadata(rsc->standard, op->op_type)) {
685
686 crm_trace("No digests needed for %s action on %s (params=%p rsc=%p)",
687 op->op_type, op->rsc_id, op->params, rsc);
688 return;
689 }
690
691 lrm_state = lrm_state_find(node_name);
692 if (lrm_state == NULL) {
693 crm_warn("Cannot calculate digests for operation " PCMK__OP_FMT
694 " because we have no connection to executor for %s",
695 op->rsc_id, op->op_type, op->interval_ms, node_name);
696 return;
697 }
698
699
700
701
702
703
704 metadata = controld_get_rsc_metadata(lrm_state, rsc,
705 controld_metadata_from_agent
706 |controld_metadata_from_cache);
707 if (metadata == NULL) {
708 return;
709 }
710
711 crm_trace("Including additional digests for %s:%s:%s",
712 rsc->standard, rsc->provider, rsc->type);
713 append_restart_list(op, metadata, xml_op, caller_version);
714 append_secure_list(op, metadata, xml_op, caller_version);
715
716 return;
717 }
718
719
720
721
722
723
724
725
726
727
728
729 bool
730 controld_record_pending_op(const char *node_name, const lrmd_rsc_info_t *rsc,
731 lrmd_event_data_t *op)
732 {
733 const char *record_pending = NULL;
734
735 CRM_CHECK((node_name != NULL) && (rsc != NULL) && (op != NULL),
736 return false);
737
738
739 if ((op->op_type == NULL) || (op->params == NULL)
740 || !controld_action_is_recordable(op->op_type)) {
741 return false;
742 }
743
744
745 record_pending = crm_meta_value(op->params, PCMK_META_RECORD_PENDING);
746 if ((record_pending != NULL) && !crm_is_true(record_pending)) {
747 return false;
748 }
749
750 op->call_id = -1;
751 op->t_run = time(NULL);
752 op->t_rcchange = op->t_run;
753
754 lrmd__set_result(op, PCMK_OCF_UNKNOWN, PCMK_EXEC_PENDING, NULL);
755
756 crm_debug("Recording pending %s-interval %s for %s on %s in the CIB",
757 pcmk__readable_interval(op->interval_ms), op->op_type, op->rsc_id,
758 node_name);
759 controld_update_resource_history(node_name, rsc, op, 0);
760 return true;
761 }
762
763 static void
764 cib_rsc_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
765 {
766 switch (rc) {
767 case pcmk_ok:
768 case -pcmk_err_diff_failed:
769 case -pcmk_err_diff_resync:
770 crm_trace("Resource history update completed (call=%d rc=%d)",
771 call_id, rc);
772 break;
773 default:
774 if (call_id > 0) {
775 crm_warn("Resource history update %d failed: %s "
776 CRM_XS " rc=%d", call_id, pcmk_strerror(rc), rc);
777 } else {
778 crm_warn("Resource history update failed: %s " CRM_XS " rc=%d",
779 pcmk_strerror(rc), rc);
780 }
781 }
782
783 if (call_id == pending_rsc_update) {
784 pending_rsc_update = 0;
785 controld_trigger_fsa();
786 }
787 }
788
789
790
791
792
793 static bool
794 should_preserve_lock(lrmd_event_data_t *op)
795 {
796 if (!pcmk_is_set(controld_globals.flags, controld_shutdown_lock_enabled)) {
797 return false;
798 }
799 if (!strcmp(op->op_type, PCMK_ACTION_STOP) && (op->rc == PCMK_OCF_OK)) {
800 return true;
801 }
802 if (!strcmp(op->op_type, PCMK_ACTION_MONITOR)
803 && (op->rc == PCMK_OCF_NOT_RUNNING)) {
804 return true;
805 }
806 return false;
807 }
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823 int
824 controld_update_cib(const char *section, xmlNode *data, int options,
825 void (*callback)(xmlNode *, int, int, xmlNode *, void *))
826 {
827 cib_t *cib = controld_globals.cib_conn;
828 int cib_rc = -ENOTCONN;
829
830 CRM_ASSERT(data != NULL);
831
832 if (cib != NULL) {
833 cib_rc = cib->cmds->modify(cib, section, data, options);
834 if (cib_rc >= 0) {
835 crm_debug("Submitted CIB update %d for %s section",
836 cib_rc, section);
837 }
838 }
839
840 if (callback == NULL) {
841 if (cib_rc < 0) {
842 crm_err("Failed to update CIB %s section: %s",
843 section, pcmk_rc_str(pcmk_legacy2rc(cib_rc)));
844 }
845
846 } else {
847 if ((cib_rc >= 0) && (callback == cib_rsc_callback)) {
848
849
850
851
852 pending_rsc_update = cib_rc;
853 }
854 fsa_register_cib_callback(cib_rc, NULL, callback);
855 }
856
857 return (cib_rc >= 0)? pcmk_rc_ok : pcmk_legacy2rc(cib_rc);
858 }
859
860
861
862
863
864
865
866
867
868
869
870
871
872 void
873 controld_update_resource_history(const char *node_name,
874 const lrmd_rsc_info_t *rsc,
875 lrmd_event_data_t *op, time_t lock_time)
876 {
877 xmlNode *update = NULL;
878 xmlNode *xml = NULL;
879 int call_opt = crmd_cib_smart_opt();
880 const char *node_id = NULL;
881 const char *container = NULL;
882
883 CRM_CHECK((node_name != NULL) && (op != NULL), return);
884
885 if (rsc == NULL) {
886 crm_warn("Resource %s no longer exists in the executor", op->rsc_id);
887 controld_ack_event_directly(NULL, NULL, rsc, op, op->rsc_id);
888 return;
889 }
890
891
892 update = pcmk__xe_create(NULL, PCMK_XE_STATUS);
893
894
895 xml = pcmk__xe_create(update, PCMK__XE_NODE_STATE);
896 if (pcmk__str_eq(node_name, controld_globals.our_nodename,
897 pcmk__str_casei)) {
898 node_id = controld_globals.our_uuid;
899 } else {
900 node_id = node_name;
901 pcmk__xe_set_bool_attr(xml, PCMK_XA_REMOTE_NODE, true);
902 }
903 crm_xml_add(xml, PCMK_XA_ID, node_id);
904 crm_xml_add(xml, PCMK_XA_UNAME, node_name);
905 crm_xml_add(xml, PCMK_XA_CRM_DEBUG_ORIGIN, __func__);
906
907
908 xml = pcmk__xe_create(xml, PCMK__XE_LRM);
909 crm_xml_add(xml, PCMK_XA_ID, node_id);
910
911
912 xml = pcmk__xe_create(xml, PCMK__XE_LRM_RESOURCES);
913
914
915 xml = pcmk__xe_create(xml, PCMK__XE_LRM_RESOURCE);
916 crm_xml_add(xml, PCMK_XA_ID, op->rsc_id);
917 crm_xml_add(xml, PCMK_XA_CLASS, rsc->standard);
918 crm_xml_add(xml, PCMK_XA_PROVIDER, rsc->provider);
919 crm_xml_add(xml, PCMK_XA_TYPE, rsc->type);
920 if (lock_time != 0) {
921
922
923
924 if (!should_preserve_lock(op)) {
925 lock_time = 0;
926 }
927 crm_xml_add_ll(xml, PCMK_OPT_SHUTDOWN_LOCK, (long long) lock_time);
928 }
929 if (op->params != NULL) {
930 container = g_hash_table_lookup(op->params,
931 CRM_META "_" PCMK__META_CONTAINER);
932 if (container != NULL) {
933 crm_trace("Resource %s is a part of container resource %s",
934 op->rsc_id, container);
935 crm_xml_add(xml, PCMK__META_CONTAINER, container);
936 }
937 }
938
939
940 controld_add_resource_history_xml(xml, rsc, op, node_name);
941
942
943
944
945
946 crm_log_xml_trace(update, __func__);
947 controld_update_cib(PCMK_XE_STATUS, update, call_opt, cib_rsc_callback);
948 free_xml(update);
949 }
950
951
952
953
954
955
956
957 void
958 controld_delete_action_history(const lrmd_event_data_t *op)
959 {
960 xmlNode *xml_top = NULL;
961
962 CRM_CHECK(op != NULL, return);
963
964 xml_top = pcmk__xe_create(NULL, PCMK__XE_LRM_RSC_OP);
965 crm_xml_add_int(xml_top, PCMK__XA_CALL_ID, op->call_id);
966 crm_xml_add(xml_top, PCMK__XA_TRANSITION_KEY, op->user_data);
967
968 if (op->interval_ms > 0) {
969 char *op_id = pcmk__op_key(op->rsc_id, op->op_type, op->interval_ms);
970
971
972 crm_xml_add(xml_top, PCMK_XA_ID, op_id);
973 free(op_id);
974 }
975
976 crm_debug("Erasing resource operation history for " PCMK__OP_FMT " (call=%d)",
977 op->rsc_id, op->op_type, op->interval_ms, op->call_id);
978
979 controld_globals.cib_conn->cmds->remove(controld_globals.cib_conn,
980 PCMK_XE_STATUS, xml_top, cib_none);
981 crm_log_xml_trace(xml_top, "op:cancel");
982 free_xml(xml_top);
983 }
984
985
986 #define XPATH_HISTORY \
987 "/" PCMK_XE_CIB "/" PCMK_XE_STATUS \
988 "/" PCMK__XE_NODE_STATE "[@" PCMK_XA_UNAME "='%s']" \
989 "/" PCMK__XE_LRM "/" PCMK__XE_LRM_RESOURCES \
990 "/" PCMK__XE_LRM_RESOURCE "[@" PCMK_XA_ID "='%s']" \
991 "/" PCMK__XE_LRM_RSC_OP
992
993
994 #define XPATH_HISTORY_ID XPATH_HISTORY "[@" PCMK_XA_ID "='%s']"
995
996
997 #define XPATH_HISTORY_CALL XPATH_HISTORY \
998 "[@" PCMK_XA_ID "='%s' and @" PCMK__XA_CALL_ID "='%d']"
999
1000
1001 #define XPATH_HISTORY_ORIG XPATH_HISTORY \
1002 "[@" PCMK_XA_ID "='%s' and @" PCMK__XA_OPERATION_KEY "='%s']"
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013 void
1014 controld_cib_delete_last_failure(const char *rsc_id, const char *node,
1015 const char *action, guint interval_ms)
1016 {
1017 char *xpath = NULL;
1018 char *last_failure_key = NULL;
1019 CRM_CHECK((rsc_id != NULL) && (node != NULL), return);
1020
1021
1022 last_failure_key = pcmk__op_key(rsc_id, "last_failure", 0);
1023 if (action == NULL) {
1024 xpath = crm_strdup_printf(XPATH_HISTORY_ID, node, rsc_id,
1025 last_failure_key);
1026 } else {
1027 char *action_key = pcmk__op_key(rsc_id, action, interval_ms);
1028
1029 xpath = crm_strdup_printf(XPATH_HISTORY_ORIG, node, rsc_id,
1030 last_failure_key, action_key);
1031 free(action_key);
1032 }
1033 free(last_failure_key);
1034
1035 controld_globals.cib_conn->cmds->remove(controld_globals.cib_conn, xpath,
1036 NULL, cib_xpath);
1037 free(xpath);
1038 }
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049 void
1050 controld_delete_action_history_by_key(const char *rsc_id, const char *node,
1051 const char *key, int call_id)
1052 {
1053 char *xpath = NULL;
1054
1055 CRM_CHECK((rsc_id != NULL) && (node != NULL) && (key != NULL), return);
1056
1057 if (call_id > 0) {
1058 xpath = crm_strdup_printf(XPATH_HISTORY_CALL, node, rsc_id, key,
1059 call_id);
1060 } else {
1061 xpath = crm_strdup_printf(XPATH_HISTORY_ID, node, rsc_id, key);
1062 }
1063 controld_globals.cib_conn->cmds->remove(controld_globals.cib_conn, xpath,
1064 NULL, cib_xpath);
1065 free(xpath);
1066 }