pacemaker 2.1.7-2.1.7
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
pcmk_simulate.c
Go to the documentation of this file.
1/*
2 * Copyright 2021-2023 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
73 &interval_ms) != pcmk_rc_ok) {
74 interval_ms = 0;
75 }
76
78 PCMK_ACTION_NOTIFIED, NULL)) {
79 const char *n_type = g_hash_table_lookup(action->meta,
80 "notify_key_type");
81 const char *n_task = g_hash_table_lookup(action->meta,
82 "notify_key_operation");
83
84 CRM_ASSERT(n_type != NULL);
85 CRM_ASSERT(n_task != NULL);
86 key = pcmk__notify_key(clone_name, n_type, n_task);
87 } else {
88 key = pcmk__op_key(clone_name, task, interval_ms);
89 }
90
91 if (action_host != NULL) {
92 action_name = crm_strdup_printf("%s%s %s",
93 prefix, key, action_host);
94 } else {
95 action_name = crm_strdup_printf("%s%s", prefix, key);
96 }
97 free(key);
98
99 } else if (pcmk__str_eq(action->task, PCMK_ACTION_STONITH,
101 const char *op = g_hash_table_lookup(action->meta, "stonith_action");
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 false, section_opts, show_opts, NULL, all, all);
157 out->end_list(out);
158
159 g_list_free(all);
160}
161
169static void
170print_transition_summary(pcmk_scheduler_t *scheduler, bool print_spacer)
171{
173
174 PCMK__OUTPUT_SPACER_IF(out, print_spacer);
175 out->begin_list(out, NULL, NULL, "Transition Summary");
177 out->end_list(out);
178}
179
190static void
191reset(pcmk_scheduler_t *scheduler, xmlNodePtr input, pcmk__output_t *out,
192 const char *use_date, unsigned int flags)
193{
195 scheduler->priv = out;
196 set_effective_date(scheduler, true, use_date);
199 }
202 }
205 }
206}
207
221static int
222write_sim_dotfile(pcmk_scheduler_t *scheduler, const char *dot_file,
223 bool all_actions, bool verbose)
224{
225 GList *iter = NULL;
226 FILE *dot_strm = fopen(dot_file, "w");
227
228 if (dot_strm == NULL) {
229 return errno;
230 }
231
232 fprintf(dot_strm, " digraph \"g\" {\n");
233 for (iter = scheduler->actions; iter != NULL; iter = iter->next) {
234 pcmk_action_t *action = (pcmk_action_t *) iter->data;
235 const char *style = "dashed";
236 const char *font = "black";
237 const char *color = "black";
238 char *action_name = create_action_name(action, verbose);
239
241 font = "orange";
242 }
243
245 style = "bold";
246 color = "green";
247
248 } else if ((action->rsc != NULL)
249 && !pcmk_is_set(action->rsc->flags, pcmk_rsc_managed)) {
250 color = "red";
251 font = "purple";
252 if (!all_actions) {
253 goto do_not_write;
254 }
255
256 } else if (pcmk_is_set(action->flags, pcmk_action_optional)) {
257 color = "blue";
258 if (!all_actions) {
259 goto do_not_write;
260 }
261
262 } else {
263 color = "red";
265 }
266
268 fprintf(dot_strm, "\"%s\" [ style=%s color=\"%s\" fontcolor=\"%s\"]\n",
269 action_name, style, color, font);
270 do_not_write:
271 free(action_name);
272 }
273
274 for (iter = scheduler->actions; iter != NULL; iter = iter->next) {
275 pcmk_action_t *action = (pcmk_action_t *) iter->data;
276
277 for (GList *before_iter = action->actions_before;
278 before_iter != NULL; before_iter = before_iter->next) {
279
280 pcmk__related_action_t *before = before_iter->data;
281
282 char *before_name = NULL;
283 char *after_name = NULL;
284 const char *style = "dashed";
285 bool optional = true;
286
287 if (before->state == pe_link_dumped) {
288 optional = false;
289 style = "bold";
290 } else if ((uint32_t) before->type == pcmk__ar_none) {
291 continue;
292 } else if (pcmk_is_set(before->action->flags,
295 && (uint32_t) before->type != pcmk__ar_if_on_same_node_or_target) {
296 optional = false;
297 }
298
299 if (all_actions || !optional) {
300 before_name = create_action_name(before->action, verbose);
301 after_name = create_action_name(action, verbose);
302 fprintf(dot_strm, "\"%s\" -> \"%s\" [ style = %s]\n",
303 before_name, after_name, style);
304 free(before_name);
305 free(after_name);
306 }
307 }
308 }
309
310 fprintf(dot_strm, "}\n");
311 fflush(dot_strm);
312 fclose(dot_strm);
313 return pcmk_rc_ok;
314}
315
328static void
329profile_file(const char *xml_file, long long repeat,
330 pcmk_scheduler_t *scheduler, const char *use_date)
331{
333 xmlNode *cib_object = NULL;
334 clock_t start = 0;
335 clock_t end;
336 unsigned long long scheduler_flags = pcmk_sched_no_compat;
337
338 CRM_ASSERT(out != NULL);
339
340 cib_object = filename2xml(xml_file);
341 start = clock();
342
343 if (pcmk_find_cib_element(cib_object, XML_CIB_TAG_STATUS) == NULL) {
345 }
346
347 if (cli_config_update(&cib_object, NULL, FALSE) == FALSE) {
348 free_xml(cib_object);
349 return;
350 }
351
352 if (validate_xml(cib_object, NULL, FALSE) != TRUE) {
353 free_xml(cib_object);
354 return;
355 }
356
358 scheduler_flags |= pcmk_sched_output_scores;
359 }
361 scheduler_flags |= pcmk_sched_show_utilization;
362 }
363
364 for (int i = 0; i < repeat; ++i) {
365 xmlNode *input = (repeat == 1)? cib_object : copy_xml(cib_object);
366
368 set_effective_date(scheduler, false, use_date);
369 pcmk__schedule_actions(input, scheduler_flags, scheduler);
371 }
372
373 end = clock();
374 out->message(out, "profile", xml_file, start, end);
375}
376
377void
378pcmk__profile_dir(const char *dir, long long repeat,
379 pcmk_scheduler_t *scheduler, const char *use_date)
380{
382 struct dirent **namelist;
383
384 int file_num = scandir(dir, &namelist, 0, alphasort);
385
386 CRM_ASSERT(out != NULL);
387
388 if (file_num > 0) {
389 struct stat prop;
390 char buffer[FILENAME_MAX];
391
392 out->begin_list(out, NULL, NULL, "Timings");
393
394 while (file_num--) {
395 if ('.' == namelist[file_num]->d_name[0]) {
396 free(namelist[file_num]);
397 continue;
398
399 } else if (!pcmk__ends_with_ext(namelist[file_num]->d_name,
400 ".xml")) {
401 free(namelist[file_num]);
402 continue;
403 }
404 snprintf(buffer, sizeof(buffer), "%s/%s",
405 dir, namelist[file_num]->d_name);
406 if (stat(buffer, &prop) == 0 && S_ISREG(prop.st_mode)) {
407 profile_file(buffer, repeat, scheduler, use_date);
408 }
409 free(namelist[file_num]);
410 }
411 free(namelist);
412
413 out->end_list(out);
414 }
415}
416
430static void
431set_effective_date(pcmk_scheduler_t *scheduler, bool print_original,
432 const char *use_date)
433{
435 time_t original_date = 0;
436
437 CRM_ASSERT(out != NULL);
438
439 crm_element_value_epoch(scheduler->input, "execution-date", &original_date);
440
441 if (use_date) {
442 scheduler->now = crm_time_new(use_date);
443 out->info(out, "Setting effective cluster time: %s", use_date);
444 crm_time_log(LOG_NOTICE, "Pretending 'now' is", scheduler->now,
446
447 } else if (original_date != 0) {
448 scheduler->now = pcmk__copy_timet(original_date);
449
450 if (print_original) {
451 char *when = crm_time_as_string(scheduler->now,
453
454 out->info(out, "Using the original execution date of: %s", when);
455 free(when);
456 }
457 }
458}
459
469static int
470simulate_pseudo_action(pcmk__graph_t *graph, pcmk__graph_action_t *action)
471{
472 const char *node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
473 const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY);
474
476 out->message(out, "inject-pseudo-action", node, task);
477
479 return pcmk_rc_ok;
480}
481
491static int
492simulate_resource_action(pcmk__graph_t *graph, pcmk__graph_action_t *action)
493{
494 int rc;
495 lrmd_event_data_t *op = NULL;
496 int target_outcome = PCMK_OCF_OK;
497
498 const char *rtype = NULL;
499 const char *rclass = NULL;
500 const char *resource = NULL;
501 const char *rprovider = NULL;
502 const char *resource_config_name = NULL;
503 const char *operation = crm_element_value(action->xml, "operation");
504 const char *target_rc_s = crm_meta_value(action->params,
506
507 xmlNode *cib_node = NULL;
508 xmlNode *cib_resource = NULL;
509 xmlNode *action_rsc = first_named_child(action->xml, XML_CIB_TAG_RESOURCE);
510
512 char *uuid = NULL;
513 const char *router_node = crm_element_value(action->xml,
515
516 // Certain actions don't need to be displayed or history entries
517 if (pcmk__str_eq(operation, CRM_OP_REPROBE, pcmk__str_none)) {
518 crm_debug("No history injection for %s op on %s", operation, node);
519 goto done; // Confirm action and update graph
520 }
521
522 if (action_rsc == NULL) { // Shouldn't be possible
523 crm_log_xml_err(action->xml, "Bad");
524 free(node);
525 return EPROTO;
526 }
527
528 /* A resource might be known by different names in the configuration and in
529 * the action (for example, a clone instance). Grab the configuration name
530 * (which is preferred when writing history), and if necessary, the instance
531 * name.
532 */
533 resource_config_name = crm_element_value(action_rsc, XML_ATTR_ID);
534 if (resource_config_name == NULL) { // Shouldn't be possible
535 crm_log_xml_err(action->xml, "No ID");
536 free(node);
537 return EPROTO;
538 }
539 resource = resource_config_name;
540 if (pe_find_resource(fake_resource_list, resource) == NULL) {
541 const char *longname = crm_element_value(action_rsc, XML_ATTR_ID_LONG);
542
543 if ((longname != NULL)
544 && (pe_find_resource(fake_resource_list, longname) != NULL)) {
545 resource = longname;
546 }
547 }
548
549 // Certain actions need to be displayed but don't need history entries
551 PCMK_ACTION_META_DATA, NULL)) {
552 out->message(out, "inject-rsc-action", resource, operation, node,
553 (guint) 0);
554 goto done; // Confirm action and update graph
555 }
556
557 rclass = crm_element_value(action_rsc, XML_AGENT_ATTR_CLASS);
558 rtype = crm_element_value(action_rsc, XML_ATTR_TYPE);
559 rprovider = crm_element_value(action_rsc, XML_AGENT_ATTR_PROVIDER);
560
561 pcmk__scan_min_int(target_rc_s, &target_outcome, 0);
562
563 CRM_ASSERT(fake_cib->cmds->query(fake_cib, NULL, NULL,
565
566 // Ensure the action node is in the CIB
568 cib_node = pcmk__inject_node(fake_cib, node,
569 ((router_node == NULL)? uuid: node));
570 free(uuid);
571 CRM_ASSERT(cib_node != NULL);
572
573 // Add a history entry for the action
574 cib_resource = pcmk__inject_resource_history(out, cib_node, resource,
575 resource_config_name,
576 rclass, rtype, rprovider);
577 if (cib_resource == NULL) {
578 crm_err("Could not simulate action %d history for resource %s",
579 action->id, resource);
580 free(node);
581 free_xml(cib_node);
582 return EINVAL;
583 }
584
585 // Simulate and display an executor event for the action result
587 target_outcome, "User-injected result");
588 out->message(out, "inject-rsc-action", resource, op->op_type, node,
589 op->interval_ms);
590
591 // Check whether action is in a list of desired simulated failures
592 for (const GList *iter = fake_op_fail_list;
593 iter != NULL; iter = iter->next) {
594 const char *spec = (const char *) iter->data;
595 char *key = NULL;
596 const char *match_name = NULL;
597
598 // Allow user to specify anonymous clone with or without instance number
599 key = crm_strdup_printf(PCMK__OP_FMT "@%s=", resource, op->op_type,
600 op->interval_ms, node);
601 if (strncasecmp(key, spec, strlen(key)) == 0) {
602 match_name = resource;
603 }
604 free(key);
605
606 // If not found, try the resource's name in the configuration
607 if ((match_name == NULL)
608 && (strcmp(resource, resource_config_name) != 0)) {
609
610 key = crm_strdup_printf(PCMK__OP_FMT "@%s=", resource_config_name,
611 op->op_type, op->interval_ms, node);
612 if (strncasecmp(key, spec, strlen(key)) == 0) {
613 match_name = resource_config_name;
614 }
615 free(key);
616 }
617
618 if (match_name == NULL) {
619 continue; // This failed action entry doesn't match
620 }
621
622 // ${match_name}_${task}_${interval_in_ms}@${node}=${rc}
623 rc = sscanf(spec, "%*[^=]=%d", (int *) &op->rc);
624 if (rc != 1) {
625 out->err(out, "Invalid failed operation '%s' "
626 "(result code must be integer)", spec);
627 continue; // Keep checking other list entries
628 }
629
630 out->info(out, "Pretending action %d failed with rc=%d",
631 action->id, op->rc);
633 graph->abort_priority = INFINITY;
634 pcmk__inject_failcount(out, cib_node, match_name, op->op_type,
635 op->interval_ms, op->rc);
636 break;
637 }
638
639 pcmk__inject_action_result(cib_resource, op, target_outcome);
640 lrmd_free_event(op);
641 rc = fake_cib->cmds->modify(fake_cib, XML_CIB_TAG_STATUS, cib_node,
643 CRM_ASSERT(rc == pcmk_ok);
644
645 done:
646 free(node);
647 free_xml(cib_node);
650 return pcmk_rc_ok;
651}
652
662static int
663simulate_cluster_action(pcmk__graph_t *graph, pcmk__graph_action_t *action)
664{
665 const char *node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
666 const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
667 xmlNode *rsc = first_named_child(action->xml, XML_CIB_TAG_RESOURCE);
668
670 out->message(out, "inject-cluster-action", node, task, rsc);
672 return pcmk_rc_ok;
673}
674
684static int
685simulate_fencing_action(pcmk__graph_t *graph, pcmk__graph_action_t *action)
686{
687 const char *op = crm_meta_value(action->params, "stonith_action");
689
690 out->message(out, "inject-fencing-action", target, op);
691
692 if (!pcmk__str_eq(op, PCMK_ACTION_ON, pcmk__str_casei)) {
693 int rc = pcmk_ok;
694 GString *xpath = g_string_sized_new(512);
695
696 // Set node state to offline
697 xmlNode *cib_node = pcmk__inject_node_state_change(fake_cib, target,
698 false);
699
700 CRM_ASSERT(cib_node != NULL);
701 crm_xml_add(cib_node, XML_ATTR_ORIGIN, __func__);
702 rc = fake_cib->cmds->replace(fake_cib, XML_CIB_TAG_STATUS, cib_node,
704 CRM_ASSERT(rc == pcmk_ok);
705
706 // Simulate controller clearing node's resource history and attributes
707 pcmk__g_strcat(xpath,
709 "[@" XML_ATTR_UNAME "='", target, "']/" XML_CIB_TAG_LRM,
710 NULL);
711 fake_cib->cmds->remove(fake_cib, (const char *) xpath->str, NULL,
713
714 g_string_truncate(xpath, 0);
715 pcmk__g_strcat(xpath,
717 "[@" XML_ATTR_UNAME "='", target, "']"
719 fake_cib->cmds->remove(fake_cib, (const char *) xpath->str, NULL,
721
722 free_xml(cib_node);
723 g_string_free(xpath, TRUE);
724 }
725
728 free(target);
729 return pcmk_rc_ok;
730}
731
734 const GList *op_fail_list)
735{
736 pcmk__graph_t *transition = NULL;
737 enum pcmk__graph_status graph_rc;
738
739 pcmk__graph_functions_t simulation_fns = {
740 simulate_pseudo_action,
741 simulate_resource_action,
742 simulate_cluster_action,
743 simulate_fencing_action,
744 };
745
746 out = scheduler->priv;
747
748 fake_cib = cib;
749 fake_op_fail_list = op_fail_list;
750
751 if (!out->is_quiet(out)) {
752 out->begin_list(out, NULL, NULL, "Executing Cluster Transition");
753 }
754
755 pcmk__set_graph_functions(&simulation_fns);
757 pcmk__log_graph(LOG_DEBUG, transition);
758
759 fake_resource_list = scheduler->resources;
760 do {
761 graph_rc = pcmk__execute_graph(transition);
762 } while (graph_rc == pcmk__graph_active);
763 fake_resource_list = NULL;
764
765 if (graph_rc != pcmk__graph_complete) {
766 out->err(out, "Transition failed: %s",
767 pcmk__graph_status2text(graph_rc));
768 pcmk__log_graph(LOG_ERR, transition);
769 out->err(out, "An invalid transition was produced");
770 }
771 pcmk__free_graph(transition);
772
773 if (!out->is_quiet(out)) {
774 // If not quiet, we'll need the resulting CIB for later display
775 xmlNode *cib_object = NULL;
776 int rc = fake_cib->cmds->query(fake_cib, NULL, &cib_object,
778
779 CRM_ASSERT(rc == pcmk_ok);
781 scheduler->input = cib_object;
782 out->end_list(out);
783 }
784 return graph_rc;
785}
786
787int
789 const pcmk_injections_t *injections, unsigned int flags,
790 uint32_t section_opts, const char *use_date,
791 const char *input_file, const char *graph_file,
792 const char *dot_file)
793{
794 int printed = pcmk_rc_no_output;
795 int rc = pcmk_rc_ok;
796 xmlNodePtr input = NULL;
797 cib_t *cib = NULL;
798
799 rc = cib__signon_query(out, &cib, &input);
800 if (rc != pcmk_rc_ok) {
801 goto simulate_done;
802 }
803
804 reset(scheduler, input, out, use_date, flags);
806
807 if ((cib->variant == cib_native)
808 && pcmk_is_set(section_opts, pcmk_section_times)) {
809 if (pcmk__our_nodename == NULL) {
810 // Currently used only in the times section
811 pcmk__query_node_name(out, 0, &pcmk__our_nodename, 0);
812 }
814 }
815
816 if (!out->is_quiet(out)) {
817 const bool show_pending = pcmk_is_set(flags, pcmk_sim_show_pending);
818
820 printed = out->message(out, "maint-mode", scheduler->flags);
821 }
822
824 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
825 printed = out->info(out,
826 "%d of %d resource instances DISABLED and "
827 "%d BLOCKED from further action due to failure",
831 }
832
833 /* Most formatted output headers use caps for each word, but this one
834 * only has the first word capitalized for compatibility with pcs.
835 */
836 print_cluster_status(scheduler, (show_pending? pcmk_show_pending : 0),
837 section_opts, "Current cluster status",
838 (printed == pcmk_rc_ok));
839 printed = pcmk_rc_ok;
840 }
841
842 // If the user requested any injections, handle them
843 if ((injections->node_down != NULL)
844 || (injections->node_fail != NULL)
845 || (injections->node_up != NULL)
846 || (injections->op_inject != NULL)
847 || (injections->ticket_activate != NULL)
848 || (injections->ticket_grant != NULL)
849 || (injections->ticket_revoke != NULL)
850 || (injections->ticket_standby != NULL)
851 || (injections->watchdog != NULL)) {
852
853 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
854 pcmk__inject_scheduler_input(scheduler, cib, injections);
855 printed = pcmk_rc_ok;
856
857 rc = cib->cmds->query(cib, NULL, &input, cib_sync_call);
858 if (rc != pcmk_rc_ok) {
859 rc = pcmk_legacy2rc(rc);
860 goto simulate_done;
861 }
862
864 reset(scheduler, input, out, use_date, flags);
866 }
867
868 if (input_file != NULL) {
869 rc = write_xml_file(input, input_file, FALSE);
870 if (rc < 0) {
871 rc = pcmk_legacy2rc(rc);
872 goto simulate_done;
873 }
874 }
875
876 if (pcmk_any_flags_set(flags, pcmk_sim_process | pcmk_sim_simulate)) {
877 pcmk__output_t *logger_out = NULL;
878 unsigned long long scheduler_flags = pcmk_sched_no_compat;
879
881 scheduler_flags |= pcmk_sched_output_scores;
882 }
884 scheduler_flags |= pcmk_sched_show_utilization;
885 }
886
887 if (pcmk_all_flags_set(scheduler->flags,
890 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
891 out->begin_list(out, NULL, NULL,
892 "Assignment Scores and Utilization Information");
893 printed = pcmk_rc_ok;
894
896 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
897 out->begin_list(out, NULL, NULL, "Assignment Scores");
898 printed = pcmk_rc_ok;
899
901 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
902 out->begin_list(out, NULL, NULL, "Utilization Information");
903 printed = pcmk_rc_ok;
904
905 } else {
906 rc = pcmk__log_output_new(&logger_out);
907 if (rc != pcmk_rc_ok) {
908 goto simulate_done;
909 }
910 pe__register_messages(logger_out);
911 pcmk__register_lib_messages(logger_out);
912 scheduler->priv = logger_out;
913 }
914
915 pcmk__schedule_actions(input, scheduler_flags, scheduler);
916
917 if (logger_out == NULL) {
918 out->end_list(out);
919 } else {
920 logger_out->finish(logger_out, CRM_EX_OK, true, NULL);
921 pcmk__output_free(logger_out);
922 scheduler->priv = out;
923 }
924
925 input = NULL; /* Don't try and free it twice */
926
927 if (graph_file != NULL) {
928 rc = write_xml_file(scheduler->graph, graph_file, FALSE);
929 if (rc < 0) {
931 goto simulate_done;
932 }
933 }
934
935 if (dot_file != NULL) {
936 rc = write_sim_dotfile(scheduler, dot_file,
939 if (rc != pcmk_rc_ok) {
941 goto simulate_done;
942 }
943 }
944
945 if (!out->is_quiet(out)) {
946 print_transition_summary(scheduler, printed == pcmk_rc_ok);
947 }
948 }
949
950 rc = pcmk_rc_ok;
951
953 goto simulate_done;
954 }
955
956 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
957 if (pcmk__simulate_transition(scheduler, cib, injections->op_fail)
960 }
961
962 if (out->is_quiet(out)) {
963 goto simulate_done;
964 }
965
966 set_effective_date(scheduler, true, use_date);
967
970 }
973 }
974
976 print_cluster_status(scheduler, 0, section_opts, "Revised Cluster Status",
977 true);
978
979simulate_done:
981 return rc;
982}
983
984int
986 const pcmk_injections_t *injections, unsigned int flags,
987 unsigned int section_opts, const char *use_date,
988 const char *input_file, const char *graph_file,
989 const char *dot_file)
990{
991 pcmk__output_t *out = NULL;
992 int rc = pcmk_rc_ok;
993
994 rc = pcmk__xml_output_new(&out, xml);
995 if (rc != pcmk_rc_ok) {
996 return rc;
997 }
998
1001
1002 rc = pcmk__simulate(scheduler, out, injections, flags, section_opts,
1003 use_date, input_file, graph_file, dot_file);
1004 pcmk__xml_output_finish(out, xml);
1005 return rc;
1006}
@ 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:340
#define PCMK_ACTION_NOTIFIED
Definition actions.h:60
#define PCMK_ACTION_DELETE
Definition actions.h:48
@ pcmk_action_runnable
Whether action is runnable.
Definition actions.h:241
@ pcmk_action_added_to_graph
Whether action has been added to transition graph.
Definition actions.h:256
@ pcmk_action_pseudo
Whether action does not require invoking an agent.
Definition actions.h:238
@ pcmk_action_optional
Whether action should not be executed.
Definition actions.h:244
#define PCMK_ACTION_STONITH
Definition actions.h:73
#define PCMK_ACTION_ON
Definition actions.h:63
#define PCMK_ACTION_NOTIFY
Definition actions.h:61
char * pcmk__notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
Definition actions.c:183
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:42
#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:1076
int cib__signon_query(pcmk__output_t *out, cib_t **cib, xmlNode **cib_object)
Definition cib_utils.c:1022
@ cib_scope_local
Definition cib_types.h:82
@ cib_xpath
Definition cib_types.h:56
@ cib_sync_call
Definition cib_types.h:102
@ 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
const char * crm_meta_value(GHashTable *hash, const char *field)
Definition utils.c:490
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:99
#define CRM_OP_REPROBE
Definition crm.h:151
#define INFINITY
Definition crm.h:98
char * crm_system_name
Definition utils.c:51
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:694
#define crm_time_log_date
Definition iso8601.h:67
crm_time_t * crm_time_new(const char *string)
Definition iso8601.c:109
#define crm_time_log(level, prefix, dt, flags)
Definition iso8601.h:60
crm_time_t * pcmk__copy_timet(time_t source)
Definition iso8601.c:1391
G_GNUC_INTERNAL xmlNode * pcmk__inject_node(cib_t *cib_conn, const char *node, const char *uuid)
G_GNUC_INTERNAL void pcmk__inject_failcount(pcmk__output_t *out, xmlNode *cib_node, const char *resource, const char *task, guint interval_ms, int rc)
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:222
#define crm_log_xml_err(xml, text)
Definition logging.h:388
#define crm_debug(fmt, args...)
Definition logging.h:384
#define crm_err(fmt, args...)
Definition logging.h:379
void lrmd_free_event(lrmd_event_data_t *event)
Free an executor event.
#define XML_LRM_ATTR_ROUTER_NODE
Definition msg_xml.h:314
#define XML_ATTR_UNAME
Definition msg_xml.h:178
#define XML_TAG_TRANSIENT_NODEATTRS
Definition msg_xml.h:420
#define XML_LRM_ATTR_TASK_KEY
Definition msg_xml.h:307
#define XML_CIB_TAG_STATE
Definition msg_xml.h:222
#define XML_LRM_ATTR_TARGET_UUID
Definition msg_xml.h:309
#define XML_ATTR_ID
Definition msg_xml.h:156
#define XML_AGENT_ATTR_PROVIDER
Definition msg_xml.h:281
#define XML_AGENT_ATTR_CLASS
Definition msg_xml.h:280
#define XML_ATTR_ID_LONG
Definition msg_xml.h:159
#define XML_ATTR_ORIGIN
Definition msg_xml.h:151
#define XML_LRM_ATTR_TASK
Definition msg_xml.h:306
#define XML_ATTR_TYPE
Definition msg_xml.h:160
#define XML_LRM_ATTR_TARGET
Definition msg_xml.h:308
#define XML_CIB_TAG_STATUS
Definition msg_xml.h:204
#define XML_CIB_TAG_LRM
Definition msg_xml.h:276
#define XML_CIB_TAG_RESOURCE
Definition msg_xml.h:235
#define XML_ATTR_TE_TARGET_RC
Definition msg_xml.h:419
#define XML_LRM_ATTR_INTERVAL_MS
Definition msg_xml.h:304
pcmk_scheduler_t * scheduler
xmlNode * input
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:447
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition nvpair.c:644
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:568
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:302
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__output_free(pcmk__output_t *out)
Definition output.c:28
int pcmk__xml_output_new(pcmk__output_t **out, xmlNodePtr *xml)
Definition output.c:236
#define PCMK__OUTPUT_SPACER_IF(out_obj, cond)
int pcmk__log_output_new(pcmk__output_t **out)
Definition output.c:272
void pcmk__xml_output_finish(pcmk__output_t *out, xmlNodePtr *xml)
Definition output.c:258
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)
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)
#define pe__set_working_set_flags(scheduler, flags_to_set)
Definition internal.h:52
void pe__register_messages(pcmk__output_t *out)
Definition pe_output.c:3162
#define pe__set_action_flags(action, flags_to_set)
Definition internal.h:76
@ pcmk_rsc_managed
Whether resource is managed.
Definition resources.h:106
Function and executable result codes.
#define CRM_ASSERT(expr)
Definition results.h:42
@ CRM_EX_OK
Success.
Definition results.h:240
@ PCMK_OCF_OK
Success.
Definition results.h:170
@ pcmk_rc_no_output
Definition results.h:124
@ pcmk_rc_ok
Definition results.h:154
@ pcmk_rc_dot_error
Definition results.h:121
@ pcmk_rc_invalid_transition
Definition results.h:119
@ pcmk_rc_graph_error
Definition results.h:120
#define pcmk_ok
Definition results.h:68
@ PCMK_EXEC_DONE
Action completed, result is known.
Definition results.h:318
int pcmk_legacy2rc(int legacy_rc)
Definition results.c:559
enum crm_exit_e crm_exit_t
Scheduler API.
@ pcmk_sched_sanitized
Whether sensitive resource attributes have been masked.
Definition scheduler.h:146
@ pcmk_sched_in_maintenance
Whether cluster is in maintenance mode (via maintenance-mode property)
Definition scheduler.h:77
@ pcmk_sched_no_compat
Definition scheduler.h:155
@ pcmk_sched_show_utilization
Whether to show node and resource utilization (in log or output)
Definition scheduler.h:161
@ pcmk_sched_output_scores
Whether node scores should be output instead of logged.
Definition scheduler.h:158
pcmk_resource_t * pe_find_resource(GList *rsc_list, const char *id_rh)
Definition status.c:391
void pe_reset_working_set(pcmk_scheduler_t *scheduler)
Reset scheduler data to default state without freeing it.
Definition status.c:338
gboolean cluster_status(pcmk_scheduler_t *scheduler)
Definition status.c:71
void cleanup_calculations(pcmk_scheduler_t *scheduler)
Reset scheduler data to defaults without freeing it or constraints.
Definition status.c:279
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:560
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:933
@ 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:1217
int(* remove)(cib_t *cib, const char *section, xmlNode *data, int call_options)
Definition cib_types.h:189
int(* query)(cib_t *cib, const char *section, xmlNode **output_data, int call_options)
Definition cib_types.h:156
int(* replace)(cib_t *cib, const char *section, xmlNode *data, int call_options)
Definition cib_types.h:187
int(* modify)(cib_t *cib, const char *section, xmlNode *data, int call_options)
Definition cib_types.h:180
cib_api_operations_t * cmds
Definition cib_types.h:345
enum cib_variant variant
Definition cib_types.h:332
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
Implementation of pcmk_action_t.
Definition actions.h:390
enum pe_action_flags flags
Group of enum pe_action_flags.
Definition actions.h:409
enum pe_ordering type
Definition actions.h:380
pcmk_action_t * action
Definition actions.h:385
enum pe_link_state state
Definition actions.h:383
Implementation of pcmk_scheduler_t.
Definition scheduler.h:172
int blocked_resources
Number of blocked resources in cluster.
Definition scheduler.h:219
int ninstances
Total number of resource instances.
Definition scheduler.h:224
GList * actions
Scheduled actions.
Definition scheduler.h:204
xmlNode * input
CIB XML.
Definition scheduler.h:175
GList * resources
Resources in cluster.
Definition scheduler.h:196
xmlNode * graph
Transition graph.
Definition scheduler.h:212
int disabled_resources
Number of disabled resources in cluster.
Definition scheduler.h:220
unsigned long long flags
Group of enum pcmk_scheduler_flags.
Definition scheduler.h:183
void * priv
For Pacemaker use only.
Definition scheduler.h:229
crm_time_t * now
Current time for evaluation purposes.
Definition scheduler.h:176
const char * localhost
Definition scheduler.h:216
xmlNode * filename2xml(const char *filename)
Definition xml.c:990
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition xml.c:2484
int write_xml_file(const xmlNode *xml, const char *filename, gboolean compress)
Write XML to a file.
Definition xml.c:1284
gboolean cli_config_update(xmlNode **xml, int *best_version, gboolean to_logs)
Definition schemas.c:1134
void free_xml(xmlNode *child)
Definition xml.c:783
gboolean validate_xml(xmlNode *xml_blob, const char *validation, gboolean to_logs)
Definition schemas.c:673
xmlNode * copy_xml(xmlNode *src_node)
Definition xml.c:789
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition xml.c:638