pacemaker 2.1.8-2.1.8
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
pcmk_simulate.c
Go to the documentation of this file.
1/*
2 * Copyright 2021-2024 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11#include <crm/cib/internal.h>
12#include <crm/common/output.h>
13#include <crm/common/results.h>
15#include <pacemaker-internal.h>
16#include <pacemaker.h>
17
18#include <stdint.h>
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <unistd.h>
22
24
25static pcmk__output_t *out = NULL;
26static cib_t *fake_cib = NULL;
27static GList *fake_resource_list = NULL;
28static const GList *fake_op_fail_list = NULL;
29
30static void set_effective_date(pcmk_scheduler_t *scheduler, bool print_original,
31 const char *use_date);
32
43static char *
44create_action_name(const pcmk_action_t *action, bool verbose)
45{
46 char *action_name = NULL;
47 const char *prefix = "";
48 const char *action_host = NULL;
49 const char *clone_name = NULL;
50 const char *task = action->task;
51
52 if (action->node != NULL) {
53 action_host = action->node->details->uname;
54 } else if (!pcmk_is_set(action->flags, pcmk_action_pseudo)) {
55 action_host = "<none>";
56 }
57
58 if (pcmk__str_eq(action->task, PCMK_ACTION_CANCEL, pcmk__str_none)) {
59 prefix = "Cancel ";
60 task = action->cancel_task;
61 }
62
63 if (action->rsc != NULL) {
64 clone_name = action->rsc->clone_name;
65 }
66
67 if (clone_name != NULL) {
68 char *key = NULL;
69 guint interval_ms = 0;
70
72 &interval_ms) != pcmk_rc_ok) {
73 interval_ms = 0;
74 }
75
77 PCMK_ACTION_NOTIFIED, NULL)) {
78 const char *n_type = g_hash_table_lookup(action->meta,
79 "notify_key_type");
80 const char *n_task = g_hash_table_lookup(action->meta,
81 "notify_key_operation");
82
83 CRM_ASSERT(n_type != NULL);
84 CRM_ASSERT(n_task != NULL);
85 key = pcmk__notify_key(clone_name, n_type, n_task);
86 } else {
87 key = pcmk__op_key(clone_name, task, interval_ms);
88 }
89
90 if (action_host != NULL) {
91 action_name = crm_strdup_printf("%s%s %s",
92 prefix, key, action_host);
93 } else {
94 action_name = crm_strdup_printf("%s%s", prefix, key);
95 }
96 free(key);
97
98 } else if (pcmk__str_eq(action->task, PCMK_ACTION_STONITH,
100 const char *op = g_hash_table_lookup(action->meta,
102
103 action_name = crm_strdup_printf("%s%s '%s' %s",
104 prefix, action->task, op, action_host);
105
106 } else if (action->rsc && action_host) {
107 action_name = crm_strdup_printf("%s%s %s",
108 prefix, action->uuid, action_host);
109
110 } else if (action_host) {
111 action_name = crm_strdup_printf("%s%s %s",
112 prefix, action->task, action_host);
113
114 } else {
115 action_name = crm_strdup_printf("%s", action->uuid);
116 }
117
118 if (verbose) {
119 char *with_id = crm_strdup_printf("%s (%d)", action_name, action->id);
120
121 free(action_name);
122 action_name = with_id;
123 }
124 return action_name;
125}
126
137static void
138print_cluster_status(pcmk_scheduler_t *scheduler, uint32_t show_opts,
139 uint32_t section_opts, const char *title,
140 bool print_spacer)
141{
143 GList *all = NULL;
144 crm_exit_t stonith_rc = 0;
146
149
150 all = g_list_prepend(all, (gpointer) "*");
151
152 PCMK__OUTPUT_SPACER_IF(out, print_spacer);
153 out->begin_list(out, NULL, NULL, "%s", title);
154 out->message(out, "cluster-status",
155 scheduler, state, stonith_rc, NULL,
156 pcmk__fence_history_none, section_opts, show_opts, NULL,
157 all, all);
158 out->end_list(out);
159
160 g_list_free(all);
161}
162
170static void
171print_transition_summary(pcmk_scheduler_t *scheduler, bool print_spacer)
172{
174
175 PCMK__OUTPUT_SPACER_IF(out, print_spacer);
176 out->begin_list(out, NULL, NULL, "Transition Summary");
178 out->end_list(out);
179}
180
191static void
192reset(pcmk_scheduler_t *scheduler, xmlNodePtr input, pcmk__output_t *out,
193 const char *use_date, unsigned int flags)
194{
196 scheduler->priv = out;
197 set_effective_date(scheduler, true, use_date);
200 }
203 }
206 }
207}
208
222static int
223write_sim_dotfile(pcmk_scheduler_t *scheduler, const char *dot_file,
224 bool all_actions, bool verbose)
225{
226 GList *iter = NULL;
227 FILE *dot_strm = fopen(dot_file, "w");
228
229 if (dot_strm == NULL) {
230 return errno;
231 }
232
233 fprintf(dot_strm, " digraph \"g\" {\n");
234 for (iter = scheduler->actions; iter != NULL; iter = iter->next) {
235 pcmk_action_t *action = (pcmk_action_t *) iter->data;
236 const char *style = "dashed";
237 const char *font = "black";
238 const char *color = "black";
239 char *action_name = create_action_name(action, verbose);
240
242 font = "orange";
243 }
244
246 style = PCMK__VALUE_BOLD;
247 color = "green";
248
249 } else if ((action->rsc != NULL)
250 && !pcmk_is_set(action->rsc->flags, pcmk_rsc_managed)) {
251 color = "red";
252 font = "purple";
253 if (!all_actions) {
254 goto do_not_write;
255 }
256
257 } else if (pcmk_is_set(action->flags, pcmk_action_optional)) {
258 color = "blue";
259 if (!all_actions) {
260 goto do_not_write;
261 }
262
263 } else {
264 color = "red";
266 }
267
269 fprintf(dot_strm, "\"%s\" [ style=%s color=\"%s\" fontcolor=\"%s\"]\n",
270 action_name, style, color, font);
271 do_not_write:
272 free(action_name);
273 }
274
275 for (iter = scheduler->actions; iter != NULL; iter = iter->next) {
276 pcmk_action_t *action = (pcmk_action_t *) iter->data;
277
278 for (GList *before_iter = action->actions_before;
279 before_iter != NULL; before_iter = before_iter->next) {
280
281 pcmk__related_action_t *before = before_iter->data;
282
283 char *before_name = NULL;
284 char *after_name = NULL;
285 const char *style = "dashed";
286 bool optional = true;
287
288 if (before->state == pe_link_dumped) {
289 optional = false;
290 style = PCMK__VALUE_BOLD;
291 } else if ((uint32_t) before->type == pcmk__ar_none) {
292 continue;
293 } else if (pcmk_is_set(before->action->flags,
296 && (uint32_t) before->type != pcmk__ar_if_on_same_node_or_target) {
297 optional = false;
298 }
299
300 if (all_actions || !optional) {
301 before_name = create_action_name(before->action, verbose);
302 after_name = create_action_name(action, verbose);
303 fprintf(dot_strm, "\"%s\" -> \"%s\" [ style = %s]\n",
304 before_name, after_name, style);
305 free(before_name);
306 free(after_name);
307 }
308 }
309 }
310
311 fprintf(dot_strm, "}\n");
312 fflush(dot_strm);
313 fclose(dot_strm);
314 return pcmk_rc_ok;
315}
316
329static void
330profile_file(const char *xml_file, long long repeat,
331 pcmk_scheduler_t *scheduler, const char *use_date)
332{
334 xmlNode *cib_object = NULL;
335 clock_t start = 0;
336 clock_t end;
337 unsigned long long scheduler_flags = pcmk_sched_no_compat;
338
339 CRM_ASSERT(out != NULL);
340
341 cib_object = pcmk__xml_read(xml_file);
342 start = clock();
343
344 if (pcmk_find_cib_element(cib_object, PCMK_XE_STATUS) == NULL) {
345 pcmk__xe_create(cib_object, PCMK_XE_STATUS);
346 }
347
348 if (pcmk__update_configured_schema(&cib_object, false) != pcmk_rc_ok) {
349 free_xml(cib_object);
350 return;
351 }
352
353 if (!pcmk__validate_xml(cib_object, NULL, NULL, NULL)) {
354 free_xml(cib_object);
355 return;
356 }
357
359 scheduler_flags |= pcmk_sched_output_scores;
360 }
362 scheduler_flags |= pcmk_sched_show_utilization;
363 }
364
365 for (int i = 0; i < repeat; ++i) {
366 xmlNode *input = cib_object;
367
368 if (repeat > 1) {
369 input = pcmk__xml_copy(NULL, cib_object);
370 }
372 set_effective_date(scheduler, false, use_date);
373 pcmk__schedule_actions(input, scheduler_flags, scheduler);
375 }
376
377 end = clock();
378 out->message(out, "profile", xml_file, start, end);
379}
380
381void
382pcmk__profile_dir(const char *dir, long long repeat,
383 pcmk_scheduler_t *scheduler, const char *use_date)
384{
386 struct dirent **namelist;
387
388 int file_num = scandir(dir, &namelist, 0, alphasort);
389
390 CRM_ASSERT(out != NULL);
391
392 if (file_num > 0) {
393 struct stat prop;
394 char buffer[FILENAME_MAX];
395
396 out->begin_list(out, NULL, NULL, "Timings");
397
398 while (file_num--) {
399 if ('.' == namelist[file_num]->d_name[0]) {
400 free(namelist[file_num]);
401 continue;
402
403 } else if (!pcmk__ends_with_ext(namelist[file_num]->d_name,
404 ".xml")) {
405 free(namelist[file_num]);
406 continue;
407 }
408 snprintf(buffer, sizeof(buffer), "%s/%s",
409 dir, namelist[file_num]->d_name);
410 if (stat(buffer, &prop) == 0 && S_ISREG(prop.st_mode)) {
411 profile_file(buffer, repeat, scheduler, use_date);
412 }
413 free(namelist[file_num]);
414 }
415 free(namelist);
416
417 out->end_list(out);
418 }
419}
420
434static void
435set_effective_date(pcmk_scheduler_t *scheduler, bool print_original,
436 const char *use_date)
437{
439 time_t original_date = 0;
440
441 CRM_ASSERT(out != NULL);
442
444 &original_date);
445
446 if (use_date) {
447 scheduler->now = crm_time_new(use_date);
448 out->info(out, "Setting effective cluster time: %s", use_date);
449 crm_time_log(LOG_NOTICE, "Pretending 'now' is", scheduler->now,
451
452 } else if (original_date != 0) {
453 scheduler->now = pcmk__copy_timet(original_date);
454
455 if (print_original) {
456 char *when = crm_time_as_string(scheduler->now,
458
459 out->info(out, "Using the original execution date of: %s", when);
460 free(when);
461 }
462 }
463}
464
474static int
475simulate_pseudo_action(pcmk__graph_t *graph, pcmk__graph_action_t *action)
476{
477 const char *node = crm_element_value(action->xml, PCMK__META_ON_NODE);
478 const char *task = crm_element_value(action->xml, PCMK__XA_OPERATION_KEY);
479
481 out->message(out, "inject-pseudo-action", node, task);
482
484 return pcmk_rc_ok;
485}
486
496static int
497simulate_resource_action(pcmk__graph_t *graph, pcmk__graph_action_t *action)
498{
499 int rc;
500 lrmd_event_data_t *op = NULL;
501 int target_outcome = PCMK_OCF_OK;
502
503 const char *rtype = NULL;
504 const char *rclass = NULL;
505 const char *resource = NULL;
506 const char *rprovider = NULL;
507 const char *resource_config_name = NULL;
508 const char *operation = crm_element_value(action->xml, PCMK_XA_OPERATION);
509 const char *target_rc_s = crm_meta_value(action->params,
511
512 xmlNode *cib_node = NULL;
513 xmlNode *cib_resource = NULL;
514 xmlNode *action_rsc = pcmk__xe_first_child(action->xml, PCMK_XE_PRIMITIVE,
515 NULL, NULL);
516
518 char *uuid = NULL;
519 const char *router_node = crm_element_value(action->xml,
521
522 // Certain actions don't need to be displayed or history entries
523 if (pcmk__str_eq(operation, CRM_OP_REPROBE, pcmk__str_none)) {
524 crm_debug("No history injection for %s op on %s", operation, node);
525 goto done; // Confirm action and update graph
526 }
527
528 if (action_rsc == NULL) { // Shouldn't be possible
529 crm_log_xml_err(action->xml, "Bad");
530 free(node);
531 return EPROTO;
532 }
533
534 /* A resource might be known by different names in the configuration and in
535 * the action (for example, a clone instance). Grab the configuration name
536 * (which is preferred when writing history), and if necessary, the instance
537 * name.
538 */
539 resource_config_name = crm_element_value(action_rsc, PCMK_XA_ID);
540 if (resource_config_name == NULL) { // Shouldn't be possible
541 crm_log_xml_err(action->xml, "No ID");
542 free(node);
543 return EPROTO;
544 }
545 resource = resource_config_name;
546 if (pe_find_resource(fake_resource_list, resource) == NULL) {
547 const char *longname = crm_element_value(action_rsc, PCMK__XA_LONG_ID);
548
549 if ((longname != NULL)
550 && (pe_find_resource(fake_resource_list, longname) != NULL)) {
551 resource = longname;
552 }
553 }
554
555 // Certain actions need to be displayed but don't need history entries
557 PCMK_ACTION_META_DATA, NULL)) {
558 out->message(out, "inject-rsc-action", resource, operation, node,
559 (guint) 0);
560 goto done; // Confirm action and update graph
561 }
562
563 rclass = crm_element_value(action_rsc, PCMK_XA_CLASS);
564 rtype = crm_element_value(action_rsc, PCMK_XA_TYPE);
565 rprovider = crm_element_value(action_rsc, PCMK_XA_PROVIDER);
566
567 pcmk__scan_min_int(target_rc_s, &target_outcome, 0);
568
569 CRM_ASSERT(fake_cib->cmds->query(fake_cib, NULL, NULL,
571
572 // Ensure the action node is in the CIB
574 cib_node = pcmk__inject_node(fake_cib, node,
575 ((router_node == NULL)? uuid: node));
576 free(uuid);
577 CRM_ASSERT(cib_node != NULL);
578
579 // Add a history entry for the action
580 cib_resource = pcmk__inject_resource_history(out, cib_node, resource,
581 resource_config_name,
582 rclass, rtype, rprovider);
583 if (cib_resource == NULL) {
584 crm_err("Could not simulate action %d history for resource %s",
585 action->id, resource);
586 free(node);
587 free_xml(cib_node);
588 return EINVAL;
589 }
590
591 // Simulate and display an executor event for the action result
593 target_outcome, "User-injected result");
594 out->message(out, "inject-rsc-action", resource, op->op_type, node,
595 op->interval_ms);
596
597 // Check whether action is in a list of desired simulated failures
598 for (const GList *iter = fake_op_fail_list;
599 iter != NULL; iter = iter->next) {
600 const char *spec = (const char *) iter->data;
601 char *key = NULL;
602 const char *match_name = NULL;
603
604 // Allow user to specify anonymous clone with or without instance number
605 key = crm_strdup_printf(PCMK__OP_FMT "@%s=", resource, op->op_type,
606 op->interval_ms, node);
607 if (strncasecmp(key, spec, strlen(key)) == 0) {
608 match_name = resource;
609 }
610 free(key);
611
612 // If not found, try the resource's name in the configuration
613 if ((match_name == NULL)
614 && (strcmp(resource, resource_config_name) != 0)) {
615
616 key = crm_strdup_printf(PCMK__OP_FMT "@%s=", resource_config_name,
617 op->op_type, op->interval_ms, node);
618 if (strncasecmp(key, spec, strlen(key)) == 0) {
619 match_name = resource_config_name;
620 }
621 free(key);
622 }
623
624 if (match_name == NULL) {
625 continue; // This failed action entry doesn't match
626 }
627
628 // ${match_name}_${task}_${interval_in_ms}@${node}=${rc}
629 rc = sscanf(spec, "%*[^=]=%d", (int *) &op->rc);
630 if (rc != 1) {
631 out->err(out, "Invalid failed operation '%s' "
632 "(result code must be integer)", spec);
633 continue; // Keep checking other list entries
634 }
635
636 out->info(out, "Pretending action %d failed with rc=%d",
637 action->id, op->rc);
640 pcmk__inject_failcount(out, fake_cib, cib_node, match_name, op->op_type,
641 op->interval_ms, op->rc);
642 break;
643 }
644
645 pcmk__inject_action_result(cib_resource, op, target_outcome);
646 lrmd_free_event(op);
647 rc = fake_cib->cmds->modify(fake_cib, PCMK_XE_STATUS, cib_node,
649 CRM_ASSERT(rc == pcmk_ok);
650
651 done:
652 free(node);
653 free_xml(cib_node);
656 return pcmk_rc_ok;
657}
658
668static int
669simulate_cluster_action(pcmk__graph_t *graph, pcmk__graph_action_t *action)
670{
671 const char *node = crm_element_value(action->xml, PCMK__META_ON_NODE);
672 const char *task = crm_element_value(action->xml, PCMK_XA_OPERATION);
673 xmlNode *rsc = pcmk__xe_first_child(action->xml, PCMK_XE_PRIMITIVE, NULL,
674 NULL);
675
677 out->message(out, "inject-cluster-action", node, task, rsc);
679 return pcmk_rc_ok;
680}
681
691static int
692simulate_fencing_action(pcmk__graph_t *graph, pcmk__graph_action_t *action)
693{
694 const char *op = crm_meta_value(action->params, PCMK__META_STONITH_ACTION);
696
697 out->message(out, "inject-fencing-action", target, op);
698
699 if (!pcmk__str_eq(op, PCMK_ACTION_ON, pcmk__str_casei)) {
700 int rc = pcmk_ok;
701 GString *xpath = g_string_sized_new(512);
702
703 // Set node state to offline
704 xmlNode *cib_node = pcmk__inject_node_state_change(fake_cib, target,
705 false);
706
707 CRM_ASSERT(cib_node != NULL);
708 crm_xml_add(cib_node, PCMK_XA_CRM_DEBUG_ORIGIN, __func__);
709 rc = fake_cib->cmds->replace(fake_cib, PCMK_XE_STATUS, cib_node,
711 CRM_ASSERT(rc == pcmk_ok);
712
713 // Simulate controller clearing node's resource history and attributes
714 pcmk__g_strcat(xpath,
716 "[@" PCMK_XA_UNAME "='", target, "']/" PCMK__XE_LRM,
717 NULL);
718 fake_cib->cmds->remove(fake_cib, (const char *) xpath->str, NULL,
720
721 g_string_truncate(xpath, 0);
722 pcmk__g_strcat(xpath,
724 "[@" PCMK_XA_UNAME "='", target, "']"
726 fake_cib->cmds->remove(fake_cib, (const char *) xpath->str, NULL,
728
729 free_xml(cib_node);
730 g_string_free(xpath, TRUE);
731 }
732
735 free(target);
736 return pcmk_rc_ok;
737}
738
741 const GList *op_fail_list)
742{
743 pcmk__graph_t *transition = NULL;
744 enum pcmk__graph_status graph_rc;
745
746 pcmk__graph_functions_t simulation_fns = {
747 simulate_pseudo_action,
748 simulate_resource_action,
749 simulate_cluster_action,
750 simulate_fencing_action,
751 };
752
753 out = scheduler->priv;
754
755 fake_cib = cib;
756 fake_op_fail_list = op_fail_list;
757
758 if (!out->is_quiet(out)) {
759 out->begin_list(out, NULL, NULL, "Executing Cluster Transition");
760 }
761
762 pcmk__set_graph_functions(&simulation_fns);
764 pcmk__log_graph(LOG_DEBUG, transition);
765
766 fake_resource_list = scheduler->resources;
767 do {
768 graph_rc = pcmk__execute_graph(transition);
769 } while (graph_rc == pcmk__graph_active);
770 fake_resource_list = NULL;
771
772 if (graph_rc != pcmk__graph_complete) {
773 out->err(out, "Transition failed: %s",
774 pcmk__graph_status2text(graph_rc));
775 pcmk__log_graph(LOG_ERR, transition);
776 out->err(out, "An invalid transition was produced");
777 }
778 pcmk__free_graph(transition);
779
780 if (!out->is_quiet(out)) {
781 // If not quiet, we'll need the resulting CIB for later display
782 xmlNode *cib_object = NULL;
783 int rc = fake_cib->cmds->query(fake_cib, NULL, &cib_object,
785
786 CRM_ASSERT(rc == pcmk_ok);
788 scheduler->input = cib_object;
789 out->end_list(out);
790 }
791 return graph_rc;
792}
793
794int
796 const pcmk_injections_t *injections, unsigned int flags,
797 uint32_t section_opts, const char *use_date,
798 const char *input_file, const char *graph_file,
799 const char *dot_file)
800{
801 int printed = pcmk_rc_no_output;
802 int rc = pcmk_rc_ok;
803 xmlNodePtr input = NULL;
804 cib_t *cib = NULL;
805
806 rc = cib__signon_query(out, &cib, &input);
807 if (rc != pcmk_rc_ok) {
808 goto simulate_done;
809 }
810
811 reset(scheduler, input, out, use_date, flags);
813
814 if ((cib->variant == cib_native)
815 && pcmk_is_set(section_opts, pcmk_section_times)) {
816 if (pcmk__our_nodename == NULL) {
817 // Currently used only in the times section
818 pcmk__query_node_name(out, 0, &pcmk__our_nodename, 0);
819 }
821 }
822
823 if (!out->is_quiet(out)) {
824 const bool show_pending = pcmk_is_set(flags, pcmk_sim_show_pending);
825
827 printed = out->message(out, "maint-mode", scheduler->flags);
828 }
829
831 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
832 printed = out->info(out,
833 "%d of %d resource instances DISABLED and "
834 "%d BLOCKED from further action due to failure",
838 }
839
840 /* Most formatted output headers use caps for each word, but this one
841 * only has the first word capitalized for compatibility with pcs.
842 */
843 print_cluster_status(scheduler, (show_pending? pcmk_show_pending : 0),
844 section_opts, "Current cluster status",
845 (printed == pcmk_rc_ok));
846 printed = pcmk_rc_ok;
847 }
848
849 // If the user requested any injections, handle them
850 if ((injections->node_down != NULL)
851 || (injections->node_fail != NULL)
852 || (injections->node_up != NULL)
853 || (injections->op_inject != NULL)
854 || (injections->ticket_activate != NULL)
855 || (injections->ticket_grant != NULL)
856 || (injections->ticket_revoke != NULL)
857 || (injections->ticket_standby != NULL)
858 || (injections->watchdog != NULL)) {
859
860 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
861 pcmk__inject_scheduler_input(scheduler, cib, injections);
862 printed = pcmk_rc_ok;
863
864 rc = cib->cmds->query(cib, NULL, &input, cib_sync_call);
865 if (rc != pcmk_rc_ok) {
866 rc = pcmk_legacy2rc(rc);
867 goto simulate_done;
868 }
869
871 reset(scheduler, input, out, use_date, flags);
873 }
874
875 if (input_file != NULL) {
876 rc = pcmk__xml_write_file(input, input_file, false, NULL);
877 if (rc != pcmk_rc_ok) {
878 goto simulate_done;
879 }
880 }
881
882 if (pcmk_any_flags_set(flags, pcmk_sim_process | pcmk_sim_simulate)) {
883 pcmk__output_t *logger_out = NULL;
884 unsigned long long scheduler_flags = pcmk_sched_no_compat;
885
887 scheduler_flags |= pcmk_sched_output_scores;
888 }
890 scheduler_flags |= pcmk_sched_show_utilization;
891 }
892
893 if (pcmk_all_flags_set(scheduler->flags,
896 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
897 out->begin_list(out, NULL, NULL,
898 "Assignment Scores and Utilization Information");
899 printed = pcmk_rc_ok;
900
902 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
903 out->begin_list(out, NULL, NULL, "Assignment Scores");
904 printed = pcmk_rc_ok;
905
907 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
908 out->begin_list(out, NULL, NULL, "Utilization Information");
909 printed = pcmk_rc_ok;
910
911 } else {
912 rc = pcmk__log_output_new(&logger_out);
913 if (rc != pcmk_rc_ok) {
914 goto simulate_done;
915 }
916 pe__register_messages(logger_out);
917 pcmk__register_lib_messages(logger_out);
918 scheduler->priv = logger_out;
919 }
920
921 pcmk__schedule_actions(input, scheduler_flags, scheduler);
922
923 if (logger_out == NULL) {
924 out->end_list(out);
925 } else {
926 logger_out->finish(logger_out, CRM_EX_OK, true, NULL);
927 pcmk__output_free(logger_out);
928 scheduler->priv = out;
929 }
930
931 input = NULL; /* Don't try and free it twice */
932
933 if (graph_file != NULL) {
934 rc = pcmk__xml_write_file(scheduler->graph, graph_file, false,
935 NULL);
936 if (rc != pcmk_rc_ok) {
938 goto simulate_done;
939 }
940 }
941
942 if (dot_file != NULL) {
943 rc = write_sim_dotfile(scheduler, dot_file,
946 if (rc != pcmk_rc_ok) {
948 goto simulate_done;
949 }
950 }
951
952 if (!out->is_quiet(out)) {
953 print_transition_summary(scheduler, printed == pcmk_rc_ok);
954 }
955 }
956
957 rc = pcmk_rc_ok;
958
960 goto simulate_done;
961 }
962
963 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
964 if (pcmk__simulate_transition(scheduler, cib, injections->op_fail)
967 }
968
969 if (out->is_quiet(out)) {
970 goto simulate_done;
971 }
972
973 set_effective_date(scheduler, true, use_date);
974
977 }
980 }
981
983 print_cluster_status(scheduler, 0, section_opts, "Revised Cluster Status",
984 true);
985
986simulate_done:
988 return rc;
989}
990
991int
993 const pcmk_injections_t *injections, unsigned int flags,
994 unsigned int section_opts, const char *use_date,
995 const char *input_file, const char *graph_file,
996 const char *dot_file)
997{
998 pcmk__output_t *out = NULL;
999 int rc = pcmk_rc_ok;
1000
1001 rc = pcmk__xml_output_new(&out, xml);
1002 if (rc != pcmk_rc_ok) {
1003 return rc;
1004 }
1005
1008
1009 rc = pcmk__simulate(scheduler, out, injections, flags, section_opts,
1010 use_date, input_file, graph_file, dot_file);
1012 return rc;
1013}
@ pcmk__ar_none
No relation (compare with equality rather than bit set)
@ pcmk__ar_if_on_same_node_or_target
Actions are ordered if on same node (or migration target for migrate_to)
#define PCMK_ACTION_CANCEL
Definition actions.h:45
#define PCMK_ACTION_META_DATA
Definition actions.h:56
@ pe_link_dumped
Definition actions.h:277
#define PCMK_ACTION_NOTIFIED
Definition actions.h:61
#define PCMK_ACTION_DELETE
Definition actions.h:48
@ pcmk_action_runnable
Definition actions.h:207
@ pcmk_action_added_to_graph
Definition actions.h:222
@ pcmk_action_pseudo
Definition actions.h:204
@ pcmk_action_optional
Definition actions.h:210
#define PCMK_ACTION_STONITH
Definition actions.h:74
#define PCMK_ACTION_ON
Definition actions.h:64
#define PCMK_ACTION_NOTIFY
Definition actions.h:62
char * pcmk__notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
Definition actions.c:337
#define pcmk__set_action_flags(action, flags_to_set)
char * pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key (RESOURCE_ACTION_INTERVAL)
Definition actions.c:196
#define PCMK__OP_FMT
printf-style format to create operation key from resource, action, interval
int cib__clean_up_connection(cib_t **cib)
Definition cib_utils.c:1046
int cib__signon_query(pcmk__output_t *out, cib_t **cib, xmlNode **cib_object)
Definition cib_utils.c:965
@ cib_scope_local
Definition cib_types.h:90
@ cib_xpath
Definition cib_types.h:63
@ cib_sync_call
Definition cib_types.h:133
@ cib_native
Definition cib_types.h:30
xmlNode * pcmk_find_cib_element(xmlNode *cib, const char *element_name)
Find an element in the CIB.
Definition cib.c:172
char * pcmk__our_nodename
Node name of the local node.
Definition logging.c:48
uint64_t flags
Definition remote.c:3
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:98
#define CRM_OP_REPROBE
Definition crm.h:136
char * crm_system_name
Definition utils.c:50
pcmk_pacemakerd_state
@ pcmk_pacemakerd_state_invalid
#define crm_time_log_timeofday
Definition iso8601.h:68
char * crm_time_as_string(const crm_time_t *dt, int flags)
Get a string representation of a crm_time_t object.
Definition iso8601.c:699
#define crm_time_log_date
Definition iso8601.h:67
crm_time_t * crm_time_new(const char *string)
Definition iso8601.c:112
#define crm_time_log(level, prefix, dt, flags)
Definition iso8601.h:60
crm_time_t * pcmk__copy_timet(time_t source)
Definition iso8601.c:1441
G_GNUC_INTERNAL void pcmk__inject_failcount(pcmk__output_t *out, cib_t *cib_conn, xmlNode *cib_node, const char *resource, const char *task, guint interval_ms, int rc)
G_GNUC_INTERNAL xmlNode * pcmk__inject_node(cib_t *cib_conn, const char *node, const char *uuid)
G_GNUC_INTERNAL xmlNode * pcmk__inject_node_state_change(cib_t *cib_conn, const char *node, bool up)
void pcmk__inject_scheduler_input(pcmk_scheduler_t *scheduler, cib_t *cib, const pcmk_injections_t *injections)
G_GNUC_INTERNAL xmlNode * pcmk__inject_action_result(xmlNode *cib_resource, lrmd_event_data_t *op, int target_rc)
G_GNUC_INTERNAL void pcmk__output_actions(pcmk_scheduler_t *scheduler)
G_GNUC_INTERNAL xmlNode * pcmk__inject_resource_history(pcmk__output_t *out, xmlNode *cib_node, const char *resource, const char *lrm_name, const char *rclass, const char *rtype, const char *rprovider)
#define CRM_LOG_ASSERT(expr)
Definition logging.h:228
#define crm_log_xml_err(xml, text)
Definition logging.h:405
#define crm_debug(fmt, args...)
Definition logging.h:400
#define crm_err(fmt, args...)
Definition logging.h:389
void lrmd_free_event(lrmd_event_data_t *event)
Free an executor event.
pcmk_scheduler_t * scheduler
xmlNode * input
const char * crm_meta_value(GHashTable *hash, const char *field)
Get the value of a meta-attribute.
Definition nvpair.c:987
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:446
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition nvpair.c:674
int crm_element_value_epoch(const xmlNode *xml, const char *name, time_t *dest)
Retrieve the seconds-since-epoch value of an XML attribute.
Definition nvpair.c:567
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition nvpair.c:301
#define PCMK_META_INTERVAL
Definition options.h:91
#define PCMK__META_ON_NODE_UUID
#define PCMK__META_ON_NODE
#define PCMK__META_OP_TARGET_RC
#define PCMK__VALUE_BOLD
#define PCMK__META_STONITH_ACTION
Control output from tools.
@ pcmk_show_failed_detail
Definition output.h:67
@ pcmk_show_pending
Definition output.h:65
@ pcmk_show_inactive_rscs
Definition output.h:63
@ pcmk_section_nodes
Definition output.h:32
@ pcmk_section_times
Definition output.h:29
@ pcmk_section_resources
Definition output.h:33
void pcmk__xml_output_finish(pcmk__output_t *out, crm_exit_t exit_status, xmlNodePtr *xml)
Definition output.c:271
void pcmk__output_free(pcmk__output_t *out)
Definition output.c:30
int pcmk__xml_output_new(pcmk__output_t **out, xmlNodePtr *xml)
Definition output.c:244
#define PCMK__OUTPUT_SPACER_IF(out_obj, cond)
int pcmk__log_output_new(pcmk__output_t **out)
Definition output.c:291
High Level API.
@ pcmk_sim_verbose
Definition pacemaker.h:43
@ pcmk_sim_sanitized
Definition pacemaker.h:42
@ pcmk_sim_show_scores
Definition pacemaker.h:39
@ pcmk_sim_simulate
Definition pacemaker.h:41
@ pcmk_sim_process
Definition pacemaker.h:38
@ pcmk_sim_show_pending
Definition pacemaker.h:37
@ pcmk_sim_all_actions
Definition pacemaker.h:36
@ pcmk_sim_show_utilization
Definition pacemaker.h:40
const char * action
Definition pcmk_fence.c:30
const char * target
Definition pcmk_fence.c:29
int pcmk__simulate(pcmk_scheduler_t *scheduler, pcmk__output_t *out, const pcmk_injections_t *injections, unsigned int flags, uint32_t section_opts, const char *use_date, const char *input_file, const char *graph_file, const char *dot_file)
void pcmk__profile_dir(const char *dir, long long repeat, pcmk_scheduler_t *scheduler, const char *use_date)
int pcmk_simulate(xmlNodePtr *xml, pcmk_scheduler_t *scheduler, const pcmk_injections_t *injections, unsigned int flags, unsigned int section_opts, const char *use_date, const char *input_file, const char *graph_file, const char *dot_file)
Simulate a cluster's response to events.
enum pcmk__graph_status pcmk__simulate_transition(pcmk_scheduler_t *scheduler, cib_t *cib, const GList *op_fail_list)
@ pcmk__fence_history_none
Definition pcmki_fence.h:19
void pcmk__register_lib_messages(pcmk__output_t *out)
void pcmk__schedule_actions(xmlNode *cib, unsigned long long flags, pcmk_scheduler_t *scheduler)
@ pcmk__graph_action_confirmed
@ pcmk__graph_action_failed
void pcmk__free_graph(pcmk__graph_t *graph)
pcmk__graph_t * pcmk__unpack_graph(const xmlNode *xml_graph, const char *reference)
void pcmk__set_graph_functions(pcmk__graph_functions_t *fns)
const char * pcmk__graph_status2text(enum pcmk__graph_status state)
enum pcmk__graph_status pcmk__execute_graph(pcmk__graph_t *graph)
lrmd_event_data_t * pcmk__event_from_graph_action(const xmlNode *resource, const pcmk__graph_action_t *action, int status, int rc, const char *exit_reason)
pcmk__graph_status
@ pcmk__graph_active
@ pcmk__graph_complete
void pcmk__update_graph(pcmk__graph_t *graph, const pcmk__graph_action_t *action)
void pcmk__log_graph(unsigned int log_level, pcmk__graph_t *graph)
#define pcmk__set_graph_action_flags(action, flags_to_set)
void pe__register_messages(pcmk__output_t *out)
Definition pe_output.c:3440
@ pcmk_rsc_managed
Definition resources.h:88
Function and executable result codes.
#define CRM_ASSERT(expr)
Definition results.h:42
@ CRM_EX_OK
Success.
Definition results.h:255
@ PCMK_OCF_OK
Success.
Definition results.h:178
@ pcmk_rc_no_output
Definition results.h:131
@ pcmk_rc_ok
Definition results.h:162
@ pcmk_rc_dot_error
Definition results.h:128
@ pcmk_rc_invalid_transition
Definition results.h:126
@ pcmk_rc_graph_error
Definition results.h:127
#define pcmk_ok
Definition results.h:69
@ PCMK_EXEC_DONE
Action completed, result is known.
Definition results.h:333
int pcmk_legacy2rc(int legacy_rc)
Definition results.c:559
enum crm_exit_e crm_exit_t
crm_exit_t pcmk_rc2exitc(int rc)
Map a function return code to the most similar exit code.
Definition results.c:702
Scheduler API.
@ pcmk_sched_sanitized
Definition scheduler.h:161
@ pcmk_sched_in_maintenance
Definition scheduler.h:86
@ pcmk_sched_no_compat
Definition scheduler.h:170
@ pcmk_sched_show_utilization
Definition scheduler.h:176
@ pcmk_sched_output_scores
Definition scheduler.h:173
#define pcmk__set_scheduler_flags(scheduler, flags_to_set)
bool pcmk__validate_xml(xmlNode *xml_blob, const char *validation, xmlRelaxNGValidityErrorFunc error_handler, void *error_handler_context)
Definition schemas.c:757
int pcmk__update_configured_schema(xmlNode **xml, bool to_logs)
Update XML from its configured schema to the latest major series.
Definition schemas.c:1257
#define PCMK_SCORE_INFINITY
Integer score to use to represent "infinity".
Definition scores.h:24
pcmk_resource_t * pe_find_resource(GList *rsc_list, const char *id_rh)
Definition status.c:430
void pe_reset_working_set(pcmk_scheduler_t *scheduler)
Reset scheduler data to default state without freeing it.
Definition status.c:377
gboolean cluster_status(pcmk_scheduler_t *scheduler)
Definition status.c:96
void cleanup_calculations(pcmk_scheduler_t *scheduler)
Reset scheduler data to defaults without freeing it or constraints.
Definition status.c:318
int pcmk__scan_min_int(const char *text, int *result, int minimum)
Definition strings.c:127
bool pcmk__ends_with_ext(const char *s, const char *match)
Definition strings.c:635
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:1026
@ pcmk__str_none
@ pcmk__str_casei
int pcmk__guint_from_hash(GHashTable *table, const char *key, guint default_val, guint *result)
Definition strings.c:311
void pcmk__g_strcat(GString *buffer,...) G_GNUC_NULL_TERMINATED
Definition strings.c:1296
int(* remove)(cib_t *cib, const char *section, xmlNode *data, int call_options)
Definition cib_types.h:237
int(* query)(cib_t *cib, const char *section, xmlNode **output_data, int call_options)
Definition cib_types.h:198
int(* replace)(cib_t *cib, const char *section, xmlNode *data, int call_options)
Definition cib_types.h:235
int(* modify)(cib_t *cib, const char *section, xmlNode *data, int call_options)
Definition cib_types.h:228
cib_api_operations_t * cmds
Definition cib_types.h:399
enum cib_variant variant
Definition cib_types.h:385
const char * op_type
Definition lrmd_events.h:43
enum ocf_exitcode rc
Definition lrmd_events.h:63
This structure contains everything that makes up a single output formatter.
void(* end_list)(pcmk__output_t *out)
int(* message)(pcmk__output_t *out, const char *message_id,...)
bool(* is_quiet)(pcmk__output_t *out)
void(* finish)(pcmk__output_t *out, crm_exit_t exit_status, bool print, void **copy_dest)
void(* begin_list)(pcmk__output_t *out, const char *singular_noun, const char *plural_noun, const char *format,...) G_GNUC_PRINTF(4
int(* info)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
int(*) int(*) void(* err)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
Synthetic cluster events that can be injected into the cluster for running simulations.
Definition pacemaker.h:50
GList * node_down
Definition pacemaker.h:54
GList * ticket_activate
Definition pacemaker.h:74
GList * ticket_grant
Definition pacemaker.h:68
GList * ticket_revoke
Definition pacemaker.h:70
GList * node_fail
Definition pacemaker.h:56
GList * op_inject
Definition pacemaker.h:61
GList * ticket_standby
Definition pacemaker.h:72
enum pe_action_flags flags
Definition actions.h:349
enum pe_ordering type
Definition actions.h:317
pcmk_action_t * action
Definition actions.h:322
enum pe_link_state state
Definition actions.h:320
xmlNode * input
Definition scheduler.h:196
GList * resources
Definition scheduler.h:231
xmlNode * graph
Definition scheduler.h:247
unsigned long long flags
Definition scheduler.h:211
crm_time_t * now
Definition scheduler.h:198
const char * localhost
Definition scheduler.h:251
void free_xml(xmlNode *child)
Definition xml.c:867
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition xml.c:883
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition xml.c:440
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition xml.c:720
int pcmk__xml_write_file(const xmlNode *xml, const char *filename, bool compress, unsigned int *nbytes)
Definition xml_io.c:688
xmlNode * pcmk__xml_read(const char *filename)
Definition xml_io.c:166
#define PCMK_XE_STATUS
Definition xml_names.h:199
#define PCMK_XA_CLASS
Definition xml_names.h:241
#define PCMK_XA_EXECUTION_DATE
Definition xml_names.h:267
#define PCMK_XA_OPERATION
Definition xml_names.h:344
#define PCMK_XA_ID
Definition xml_names.h:296
#define PCMK_XA_PROVIDER
Definition xml_names.h:359
#define PCMK_XE_PRIMITIVE
Definition xml_names.h:160
#define PCMK_XA_TYPE
Definition xml_names.h:425
#define PCMK_XA_CRM_DEBUG_ORIGIN
Definition xml_names.h:248
#define PCMK_XA_UNAME
Definition xml_names.h:426
#define PCMK__XE_TRANSIENT_ATTRIBUTES
#define PCMK__XA_ROUTER_NODE
#define PCMK__XA_OPERATION_KEY
#define PCMK__XE_NODE_STATE
#define PCMK__XE_LRM
#define PCMK__XA_LONG_ID