pacemaker 2.1.4-dc6eb4362e
Scalable High-Availability cluster resource manager
pcmk_simulate.c
Go to the documentation of this file.
1/*
2 * Copyright 2021-2022 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
25#define STATUS_PATH_MAX 512
26
27static pcmk__output_t *out = NULL;
28static cib_t *fake_cib = NULL;
29static GList *fake_resource_list = NULL;
30static GList *fake_op_fail_list = NULL;
31
32static void set_effective_date(pe_working_set_t *data_set, bool print_original,
33 char *use_date);
34
45static char *
46create_action_name(pe_action_t *action, bool verbose)
47{
48 char *action_name = NULL;
49 const char *prefix = "";
50 const char *action_host = NULL;
51 const char *clone_name = NULL;
52 const char *task = action->task;
53
54 if (action->node != NULL) {
55 action_host = action->node->details->uname;
56 } else if (!pcmk_is_set(action->flags, pe_action_pseudo)) {
57 action_host = "<none>";
58 }
59
60 if (pcmk__str_eq(action->task, RSC_CANCEL, pcmk__str_none)) {
61 prefix = "Cancel ";
62 task = action->cancel_task;
63 }
64
65 if (action->rsc != NULL) {
66 clone_name = action->rsc->clone_name;
67 }
68
69 if (clone_name != NULL) {
70 char *key = NULL;
71 guint interval_ms = 0;
72
75 &interval_ms) != pcmk_rc_ok) {
76 interval_ms = 0;
77 }
78
80 NULL)) {
81 const char *n_type = g_hash_table_lookup(action->meta,
82 "notify_key_type");
83 const char *n_task = g_hash_table_lookup(action->meta,
84 "notify_key_operation");
85
86 CRM_ASSERT(n_type != NULL);
87 CRM_ASSERT(n_task != NULL);
88 key = pcmk__notify_key(clone_name, n_type, n_task);
89 } else {
90 key = pcmk__op_key(clone_name, task, interval_ms);
91 }
92
93 if (action_host != NULL) {
94 action_name = crm_strdup_printf("%s%s %s",
95 prefix, key, action_host);
96 } else {
97 action_name = crm_strdup_printf("%s%s", prefix, key);
98 }
99 free(key);
100
101 } else if (pcmk__str_eq(action->task, CRM_OP_FENCE, pcmk__str_casei)) {
102 const char *op = g_hash_table_lookup(action->meta, "stonith_action");
103
104 action_name = crm_strdup_printf("%s%s '%s' %s",
105 prefix, action->task, op, action_host);
106
107 } else if (action->rsc && action_host) {
108 action_name = crm_strdup_printf("%s%s %s",
109 prefix, action->uuid, action_host);
110
111 } else if (action_host) {
112 action_name = crm_strdup_printf("%s%s %s",
113 prefix, action->task, action_host);
114
115 } else {
116 action_name = crm_strdup_printf("%s", action->uuid);
117 }
118
119 if (verbose) {
120 char *with_id = crm_strdup_printf("%s (%d)", action_name, action->id);
121
122 free(action_name);
123 action_name = with_id;
124 }
125 return action_name;
126}
127
138static void
139print_cluster_status(pe_working_set_t *data_set, uint32_t show_opts,
140 uint32_t section_opts, const char *title, bool print_spacer)
141{
143 GList *all = NULL;
144 crm_exit_t stonith_rc = 0;
145
148
149 all = g_list_prepend(all, (gpointer) "*");
150
151 PCMK__OUTPUT_SPACER_IF(out, print_spacer);
152 out->begin_list(out, NULL, NULL, "%s", title);
153 out->message(out, "cluster-status", data_set, stonith_rc, NULL, FALSE,
154 section_opts, show_opts, NULL, all, all);
155 out->end_list(out);
156
157 g_list_free(all);
158}
159
167static void
168print_transition_summary(pe_working_set_t *data_set, bool print_spacer)
169{
171
172 PCMK__OUTPUT_SPACER_IF(out, print_spacer);
173 out->begin_list(out, NULL, NULL, "Transition Summary");
175 out->end_list(out);
176}
177
188static void
189reset(pe_working_set_t *data_set, xmlNodePtr input, pcmk__output_t *out,
190 char *use_date, unsigned int flags)
191{
193 data_set->priv = out;
194 set_effective_date(data_set, true, use_date);
197 }
200 }
203 }
204}
205
219static int
220write_sim_dotfile(pe_working_set_t *data_set, const char *dot_file,
221 bool all_actions, bool verbose)
222{
223 GList *gIter = NULL;
224 FILE *dot_strm = fopen(dot_file, "w");
225
226 if (dot_strm == NULL) {
227 return errno;
228 }
229
230 fprintf(dot_strm, " digraph \"g\" {\n");
231 for (gIter = data_set->actions; gIter != NULL; gIter = gIter->next) {
232 pe_action_t *action = (pe_action_t *) gIter->data;
233 const char *style = "dashed";
234 const char *font = "black";
235 const char *color = "black";
236 char *action_name = create_action_name(action, verbose);
237
238 if (pcmk_is_set(action->flags, pe_action_pseudo)) {
239 font = "orange";
240 }
241
242 if (pcmk_is_set(action->flags, pe_action_dumped)) {
243 style = "bold";
244 color = "green";
245
246 } else if ((action->rsc != NULL)
247 && !pcmk_is_set(action->rsc->flags, pe_rsc_managed)) {
248 color = "red";
249 font = "purple";
250 if (!all_actions) {
251 goto do_not_write;
252 }
253
254 } else if (pcmk_is_set(action->flags, pe_action_optional)) {
255 color = "blue";
256 if (!all_actions) {
257 goto do_not_write;
258 }
259
260 } else {
261 color = "red";
263 }
264
266 fprintf(dot_strm, "\"%s\" [ style=%s color=\"%s\" fontcolor=\"%s\"]\n",
267 action_name, style, color, font);
268 do_not_write:
269 free(action_name);
270 }
271
272 for (gIter = data_set->actions; gIter != NULL; gIter = gIter->next) {
273 pe_action_t *action = (pe_action_t *) gIter->data;
274
275 GList *gIter2 = NULL;
276
277 for (gIter2 = action->actions_before; gIter2 != NULL; gIter2 = gIter2->next) {
278 pe_action_wrapper_t *before = (pe_action_wrapper_t *) gIter2->data;
279
280 char *before_name = NULL;
281 char *after_name = NULL;
282 const char *style = "dashed";
283 bool optional = true;
284
285 if (before->state == pe_link_dumped) {
286 optional = false;
287 style = "bold";
288 } else if (before->type == pe_order_none) {
289 continue;
290 } else if (pcmk_is_set(before->action->flags, pe_action_dumped)
292 && before->type != pe_order_load) {
293 optional = false;
294 }
295
296 if (all_actions || !optional) {
297 before_name = create_action_name(before->action, verbose);
298 after_name = create_action_name(action, verbose);
299 fprintf(dot_strm, "\"%s\" -> \"%s\" [ style = %s]\n",
300 before_name, after_name, style);
301 free(before_name);
302 free(after_name);
303 }
304 }
305 }
306
307 fprintf(dot_strm, "}\n");
308 fflush(dot_strm);
309 fclose(dot_strm);
310 return pcmk_rc_ok;
311}
312
325static void
326profile_file(const char *xml_file, long long repeat, pe_working_set_t *data_set,
327 char *use_date)
328{
330 xmlNode *cib_object = NULL;
331 clock_t start = 0;
332 clock_t end;
333 unsigned long long data_set_flags = pe_flag_no_compat;
334
335 CRM_ASSERT(out != NULL);
336
337 cib_object = filename2xml(xml_file);
338 start = clock();
339
340 if (pcmk_find_cib_element(cib_object, XML_CIB_TAG_STATUS) == NULL) {
342 }
343
344 if (cli_config_update(&cib_object, NULL, FALSE) == FALSE) {
345 free_xml(cib_object);
346 return;
347 }
348
349 if (validate_xml(cib_object, NULL, FALSE) != TRUE) {
350 free_xml(cib_object);
351 return;
352 }
353
355 data_set_flags |= pe_flag_show_scores;
356 }
358 data_set_flags |= pe_flag_show_utilization;
359 }
360
361 for (int i = 0; i < repeat; ++i) {
362 xmlNode *input = (repeat == 1)? cib_object : copy_xml(cib_object);
363
365 set_effective_date(data_set, false, use_date);
366 pcmk__schedule_actions(input, data_set_flags, data_set);
368 }
369
370 end = clock();
371 out->message(out, "profile", xml_file, start, end);
372}
373
374void
375pcmk__profile_dir(const char *dir, long long repeat, pe_working_set_t *data_set, char *use_date)
376{
378 struct dirent **namelist;
379
380 int file_num = scandir(dir, &namelist, 0, alphasort);
381
382 CRM_ASSERT(out != NULL);
383
384 if (file_num > 0) {
385 struct stat prop;
386 char buffer[FILENAME_MAX];
387
388 out->begin_list(out, NULL, NULL, "Timings");
389
390 while (file_num--) {
391 if ('.' == namelist[file_num]->d_name[0]) {
392 free(namelist[file_num]);
393 continue;
394
395 } else if (!pcmk__ends_with_ext(namelist[file_num]->d_name,
396 ".xml")) {
397 free(namelist[file_num]);
398 continue;
399 }
400 snprintf(buffer, sizeof(buffer), "%s/%s", dir, namelist[file_num]->d_name);
401 if (stat(buffer, &prop) == 0 && S_ISREG(prop.st_mode)) {
402 profile_file(buffer, repeat, data_set, use_date);
403 }
404 free(namelist[file_num]);
405 }
406 free(namelist);
407
408 out->end_list(out);
409 }
410}
411
425static void
426set_effective_date(pe_working_set_t *data_set, bool print_original,
427 char *use_date)
428{
430 time_t original_date = 0;
431
432 CRM_ASSERT(out != NULL);
433
434 crm_element_value_epoch(data_set->input, "execution-date", &original_date);
435
436 if (use_date) {
437 data_set->now = crm_time_new(use_date);
438 out->info(out, "Setting effective cluster time: %s", use_date);
439 crm_time_log(LOG_NOTICE, "Pretending 'now' is", data_set->now,
441
442 } else if (original_date) {
443
444 data_set->now = crm_time_new(NULL);
445 crm_time_set_timet(data_set->now, &original_date);
446
447 if (print_original) {
448 char *when = crm_time_as_string(data_set->now,
450
451 out->info(out, "Using the original execution date of: %s", when);
452 free(when);
453 }
454 }
455}
456
466static gboolean
467simulate_pseudo_action(crm_graph_t *graph, crm_action_t *action)
468{
469 const char *node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
470 const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY);
471
473 out->message(out, "inject-pseudo-action", node, task);
474
476 return TRUE;
477}
478
488static gboolean
489simulate_resource_action(crm_graph_t *graph, crm_action_t *action)
490{
491 int rc;
492 lrmd_event_data_t *op = NULL;
493 int target_outcome = PCMK_OCF_OK;
494
495 const char *rtype = NULL;
496 const char *rclass = NULL;
497 const char *resource = NULL;
498 const char *rprovider = NULL;
499 const char *resource_config_name = NULL;
500 const char *operation = crm_element_value(action->xml, "operation");
501 const char *target_rc_s = crm_meta_value(action->params,
503
504 xmlNode *cib_node = NULL;
505 xmlNode *cib_resource = NULL;
506 xmlNode *action_rsc = first_named_child(action->xml, XML_CIB_TAG_RESOURCE);
507
509 char *uuid = NULL;
510 const char *router_node = crm_element_value(action->xml,
512
513 // Certain actions don't need to be displayed or history entries
514 if (pcmk__str_eq(operation, CRM_OP_REPROBE, pcmk__str_none)) {
515 crm_debug("No history injection for %s op on %s", operation, node);
516 goto done; // Confirm action and update graph
517 }
518
519 if (action_rsc == NULL) { // Shouldn't be possible
520 crm_log_xml_err(action->xml, "Bad");
521 free(node);
522 return FALSE;
523 }
524
525 /* A resource might be known by different names in the configuration and in
526 * the action (for example, a clone instance). Grab the configuration name
527 * (which is preferred when writing history), and if necessary, the instance
528 * name.
529 */
530 resource_config_name = crm_element_value(action_rsc, XML_ATTR_ID);
531 if (resource_config_name == NULL) { // Shouldn't be possible
532 crm_log_xml_err(action->xml, "No ID");
533 free(node);
534 return FALSE;
535 }
536 resource = resource_config_name;
537 if (pe_find_resource(fake_resource_list, resource) == NULL) {
538 const char *longname = crm_element_value(action_rsc, XML_ATTR_ID_LONG);
539
540 if ((longname != NULL)
541 && (pe_find_resource(fake_resource_list, longname) != NULL)) {
542 resource = longname;
543 }
544 }
545
546 // Certain actions need to be displayed but don't need history entries
547 if (pcmk__strcase_any_of(operation, "delete", RSC_METADATA, NULL)) {
548 out->message(out, "inject-rsc-action", resource, operation, node,
549 (guint) 0);
550 goto done; // Confirm action and update graph
551 }
552
553 rclass = crm_element_value(action_rsc, XML_AGENT_ATTR_CLASS);
554 rtype = crm_element_value(action_rsc, XML_ATTR_TYPE);
555 rprovider = crm_element_value(action_rsc, XML_AGENT_ATTR_PROVIDER);
556
557 pcmk__scan_min_int(target_rc_s, &target_outcome, 0);
558
559 CRM_ASSERT(fake_cib->cmds->query(fake_cib, NULL, NULL,
561
562 // Ensure the action node is in the CIB
564 cib_node = pcmk__inject_node(fake_cib, node,
565 ((router_node == NULL)? uuid: node));
566 free(uuid);
567 CRM_ASSERT(cib_node != NULL);
568
569 // Add a history entry for the action
570 cib_resource = pcmk__inject_resource_history(out, cib_node, resource,
571 resource_config_name,
572 rclass, rtype, rprovider);
573 if (cib_resource == NULL) {
574 crm_err("Could not simulate action %d history for resource %s",
575 action->id, resource);
576 free(node);
577 free_xml(cib_node);
578 return FALSE;
579 }
580
581 // Simulate and display an executor event for the action result
583 target_outcome, "User-injected result");
584 out->message(out, "inject-rsc-action", resource, op->op_type, node,
585 op->interval_ms);
586
587 // Check whether action is in a list of desired simulated failures
588 for (GList *iter = fake_op_fail_list; iter != NULL; iter = iter->next) {
589 char *spec = (char *) iter->data;
590 char *key = NULL;
591 const char *match_name = NULL;
592
593 // Allow user to specify anonymous clone with or without instance number
594 key = crm_strdup_printf(PCMK__OP_FMT "@%s=", resource, op->op_type,
595 op->interval_ms, node);
596 if (strncasecmp(key, spec, strlen(key)) == 0) {
597 match_name = resource;
598 }
599 free(key);
600
601 // If not found, try the resource's name in the configuration
602 if ((match_name == NULL)
603 && (strcmp(resource, resource_config_name) != 0)) {
604
605 key = crm_strdup_printf(PCMK__OP_FMT "@%s=", resource_config_name,
606 op->op_type, op->interval_ms, node);
607 if (strncasecmp(key, spec, strlen(key)) == 0) {
608 match_name = resource_config_name;
609 }
610 free(key);
611 }
612
613 if (match_name == NULL) {
614 continue; // This failed action entry doesn't match
615 }
616
617 // ${match_name}_${task}_${interval_in_ms}@${node}=${rc}
618 rc = sscanf(spec, "%*[^=]=%d", (int *) &op->rc);
619 if (rc != 1) {
620 out->err(out, "Invalid failed operation '%s' "
621 "(result code must be integer)", spec);
622 continue; // Keep checking other list entries
623 }
624
625 out->info(out, "Pretending action %d failed with rc=%d",
626 action->id, op->rc);
628 graph->abort_priority = INFINITY;
629 pcmk__inject_failcount(out, cib_node, match_name, op->op_type,
630 op->interval_ms, op->rc);
631 break;
632 }
633
634 pcmk__inject_action_result(cib_resource, op, target_outcome);
635 lrmd_free_event(op);
636 rc = fake_cib->cmds->modify(fake_cib, XML_CIB_TAG_STATUS, cib_node,
638 CRM_ASSERT(rc == pcmk_ok);
639
640 done:
641 free(node);
642 free_xml(cib_node);
645 return TRUE;
646}
647
657static gboolean
658simulate_cluster_action(crm_graph_t *graph, crm_action_t *action)
659{
660 const char *node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
661 const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
662 xmlNode *rsc = first_named_child(action->xml, XML_CIB_TAG_RESOURCE);
663
665 out->message(out, "inject-cluster-action", node, task, rsc);
667 return TRUE;
668}
669
679static gboolean
680simulate_fencing_action(crm_graph_t *graph, crm_action_t *action)
681{
682 const char *op = crm_meta_value(action->params, "stonith_action");
684
685 out->message(out, "inject-fencing-action", target, op);
686
687 if (!pcmk__str_eq(op, "on", pcmk__str_casei)) {
688 int rc = pcmk_ok;
689 char xpath[STATUS_PATH_MAX];
690
691 // Set node state to offline
692 xmlNode *cib_node = pcmk__inject_node_state_change(fake_cib, target,
693 false);
694
695 CRM_ASSERT(cib_node != NULL);
696 crm_xml_add(cib_node, XML_ATTR_ORIGIN, __func__);
697 rc = fake_cib->cmds->replace(fake_cib, XML_CIB_TAG_STATUS, cib_node,
699 CRM_ASSERT(rc == pcmk_ok);
700
701 // Simulate controller clearing node's resource history and attributes
702 snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s",
704 fake_cib->cmds->remove(fake_cib, xpath, NULL,
706
707 snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s",
709 fake_cib->cmds->remove(fake_cib, xpath, NULL,
711
712 free_xml(cib_node);
713 }
714
717 free(target);
718 return TRUE;
719}
720
723 GList *op_fail_list)
724{
725 crm_graph_t *transition = NULL;
726 enum transition_status graph_rc;
727
728 crm_graph_functions_t simulation_fns = {
729 simulate_pseudo_action,
730 simulate_resource_action,
731 simulate_cluster_action,
732 simulate_fencing_action,
733 };
734
735 out = data_set->priv;
736
737 fake_cib = cib;
738 fake_op_fail_list = op_fail_list;
739
740 if (!out->is_quiet(out)) {
741 out->begin_list(out, NULL, NULL, "Executing Cluster Transition");
742 }
743
744 pcmk__set_graph_functions(&simulation_fns);
746 pcmk__log_graph(LOG_DEBUG, transition);
747
748 fake_resource_list = data_set->resources;
749 do {
750 graph_rc = pcmk__execute_graph(transition);
751 } while (graph_rc == transition_active);
752 fake_resource_list = NULL;
753
754 if (graph_rc != transition_complete) {
755 out->err(out, "Transition failed: %s",
756 pcmk__graph_status2text(graph_rc));
757 pcmk__log_graph(LOG_ERR, transition);
758 out->err(out, "An invalid transition was produced");
759 }
760 pcmk__free_graph(transition);
761
762 if (!out->is_quiet(out)) {
763 // If not quiet, we'll need the resulting CIB for later display
764 xmlNode *cib_object = NULL;
765 int rc = fake_cib->cmds->query(fake_cib, NULL, &cib_object,
767
768 CRM_ASSERT(rc == pcmk_ok);
770 data_set->input = cib_object;
771 out->end_list(out);
772 }
773 return graph_rc;
774}
775
776int
778 pcmk_injections_t *injections, unsigned int flags,
779 uint32_t section_opts, char *use_date, char *input_file,
780 char *graph_file, char *dot_file)
781{
782 int printed = pcmk_rc_no_output;
783 int rc = pcmk_rc_ok;
784 xmlNodePtr input = NULL;
785 cib_t *cib = NULL;
786
787 rc = cib__signon_query(&cib, &input);
788 if (rc != pcmk_rc_ok) {
789 goto simulate_done;
790 }
791
792 reset(data_set, input, out, use_date, flags);
794
795 if (!out->is_quiet(out)) {
797 printed = out->message(out, "maint-mode", data_set->flags);
798 }
799
801 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
802 printed = out->info(out,
803 "%d of %d resource instances DISABLED and "
804 "%d BLOCKED from further action due to failure",
808 }
809
810 /* Most formatted output headers use caps for each word, but this one
811 * only has the first word capitalized for compatibility with pcs.
812 */
813 print_cluster_status(data_set,
815 section_opts, "Current cluster status",
816 (printed == pcmk_rc_ok));
817 printed = pcmk_rc_ok;
818 }
819
820 // If the user requested any injections, handle them
821 if ((injections->node_down != NULL)
822 || (injections->node_fail != NULL)
823 || (injections->node_up != NULL)
824 || (injections->op_inject != NULL)
825 || (injections->ticket_activate != NULL)
826 || (injections->ticket_grant != NULL)
827 || (injections->ticket_revoke != NULL)
828 || (injections->ticket_standby != NULL)
829 || (injections->watchdog != NULL)) {
830
831 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
832 pcmk__inject_scheduler_input(data_set, cib, injections);
833 printed = pcmk_rc_ok;
834
835 rc = cib->cmds->query(cib, NULL, &input, cib_sync_call);
836 if (rc != pcmk_rc_ok) {
837 rc = pcmk_legacy2rc(rc);
838 goto simulate_done;
839 }
840
842 reset(data_set, input, out, use_date, flags);
844 }
845
846 if (input_file != NULL) {
847 rc = write_xml_file(input, input_file, FALSE);
848 if (rc < 0) {
849 rc = pcmk_legacy2rc(rc);
850 goto simulate_done;
851 }
852 }
853
854 if (pcmk_any_flags_set(flags, pcmk_sim_process | pcmk_sim_simulate)) {
855 pcmk__output_t *logger_out = NULL;
856 unsigned long long data_set_flags = pe_flag_no_compat;
857
859 data_set_flags |= pe_flag_show_scores;
860 }
862 data_set_flags |= pe_flag_show_utilization;
863 }
864
865 if (pcmk_all_flags_set(data_set->flags,
867 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
868 out->begin_list(out, NULL, NULL,
869 "Allocation Scores and Utilization Information");
870 printed = pcmk_rc_ok;
871
873 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
874 out->begin_list(out, NULL, NULL, "Allocation Scores");
875 printed = pcmk_rc_ok;
876
878 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
879 out->begin_list(out, NULL, NULL, "Utilization Information");
880 printed = pcmk_rc_ok;
881
882 } else {
883 logger_out = pcmk__new_logger();
884 if (logger_out == NULL) {
885 rc = pcmk_rc_error;
886 goto simulate_done;
887 }
888 data_set->priv = logger_out;
889 }
890
891 pcmk__schedule_actions(input, data_set_flags, data_set);
892
893 if (logger_out == NULL) {
894 out->end_list(out);
895 } else {
896 logger_out->finish(logger_out, CRM_EX_OK, true, NULL);
897 pcmk__output_free(logger_out);
898 data_set->priv = out;
899 }
900
901 input = NULL; /* Don't try and free it twice */
902
903 if (graph_file != NULL) {
904 rc = write_xml_file(data_set->graph, graph_file, FALSE);
905 if (rc < 0) {
907 goto simulate_done;
908 }
909 }
910
911 if (dot_file != NULL) {
912 rc = write_sim_dotfile(data_set, dot_file,
915 if (rc != pcmk_rc_ok) {
917 goto simulate_done;
918 }
919 }
920
921 if (!out->is_quiet(out)) {
922 print_transition_summary(data_set, printed == pcmk_rc_ok);
923 }
924 }
925
926 rc = pcmk_rc_ok;
927
929 goto simulate_done;
930 }
931
932 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
934 injections->op_fail) != transition_complete) {
936 }
937
938 if (out->is_quiet(out)) {
939 goto simulate_done;
940 }
941
942 set_effective_date(data_set, true, use_date);
943
946 }
949 }
950
952 print_cluster_status(data_set, 0, section_opts, "Revised Cluster Status",
953 true);
954
955simulate_done:
957 return rc;
958}
959
960int
962 pcmk_injections_t *injections, unsigned int flags,
963 unsigned int section_opts, char *use_date, char *input_file,
964 char *graph_file, char *dot_file)
965{
966 pcmk__output_t *out = NULL;
967 int rc = pcmk_rc_ok;
968
969 rc = pcmk__out_prologue(&out, xml);
970 if (rc != pcmk_rc_ok) {
971 return rc;
972 }
973
976
977 rc = pcmk__simulate(data_set, out, injections, flags, section_opts,
978 use_date, input_file, graph_file, dot_file);
979 pcmk__out_epilogue(out, xml, rc);
980 return rc;
981}
int cib__clean_up_connection(cib_t **cib)
Definition: cib_utils.c:752
int cib__signon_query(cib_t **cib, xmlNode **cib_object)
Definition: cib_utils.c:716
@ cib_scope_local
Definition: cib_types.h:59
@ cib_xpath
Definition: cib_types.h:52
@ cib_sync_call
Definition: cib_types.h:61
xmlNode * pcmk_find_cib_element(xmlNode *cib, const char *element_name)
Find an element in the CIB.
Definition: cib.c:153
char * pcmk__notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
Definition: operations.c:229
char * pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key (RESOURCE_ACTION_INTERVAL)
Definition: operations.c:45
#define PCMK__OP_FMT
Definition: internal.h:215
uint64_t flags
Definition: remote.c:3
const char * crm_meta_value(GHashTable *hash, const char *field)
Definition: utils.c:461
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:122
#define RSC_METADATA
Definition: crm.h:216
#define CRM_OP_REPROBE
Definition: crm.h:154
#define RSC_NOTIFY
Definition: crm.h:212
#define RSC_NOTIFIED
Definition: crm.h:213
#define INFINITY
Definition: crm.h:99
char * crm_system_name
Definition: utils.c:54
#define CRM_OP_FENCE
Definition: crm.h:145
#define RSC_CANCEL
Definition: crm.h:196
#define crm_time_log_timeofday
Definition: iso8601.h:67
char * crm_time_as_string(crm_time_t *dt, int flags)
Definition: iso8601.c:496
void crm_time_set_timet(crm_time_t *target, time_t *source)
Definition: iso8601.c:1255
#define crm_time_log_date
Definition: iso8601.h:66
crm_time_t * crm_time_new(const char *string)
Definition: iso8601.c:92
#define crm_time_log(level, prefix, dt, flags)
Definition: iso8601.h:60
G_GNUC_INTERNAL void pcmk__output_actions(pe_working_set_t *data_set)
G_GNUC_INTERNAL xmlNode * pcmk__inject_node(cib_t *cib_conn, const char *node, const char *uuid)
void pcmk__inject_scheduler_input(pe_working_set_t *data_set, cib_t *cib, pcmk_injections_t *injections)
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)
G_GNUC_INTERNAL xmlNode * pcmk__inject_action_result(xmlNode *cib_resource, lrmd_event_data_t *op, int target_rc)
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:210
#define crm_log_xml_err(xml, text)
Definition: logging.h:367
#define crm_debug(fmt, args...)
Definition: logging.h:363
#define crm_err(fmt, args...)
Definition: logging.h:358
void lrmd_free_event(lrmd_event_data_t *event)
Free an executor event.
Definition: lrmd_client.c:243
#define XML_LRM_ATTR_ROUTER_NODE
Definition: msg_xml.h:311
#define XML_TAG_TRANSIENT_NODEATTRS
Definition: msg_xml.h:409
#define XML_LRM_ATTR_TASK_KEY
Definition: msg_xml.h:304
#define XML_LRM_ATTR_TARGET_UUID
Definition: msg_xml.h:306
#define XML_ATTR_ID
Definition: msg_xml.h:135
#define XML_AGENT_ATTR_PROVIDER
Definition: msg_xml.h:273
#define XML_AGENT_ATTR_CLASS
Definition: msg_xml.h:272
#define XML_ATTR_ID_LONG
Definition: msg_xml.h:137
#define XML_ATTR_ORIGIN
Definition: msg_xml.h:130
#define XML_LRM_ATTR_TASK
Definition: msg_xml.h:303
#define XML_ATTR_TYPE
Definition: msg_xml.h:138
#define XML_LRM_ATTR_TARGET
Definition: msg_xml.h:305
#define XML_CIB_TAG_STATUS
Definition: msg_xml.h:185
#define XML_CIB_TAG_LRM
Definition: msg_xml.h:268
#define XML_CIB_TAG_RESOURCE
Definition: msg_xml.h:220
#define XML_ATTR_TE_TARGET_RC
Definition: msg_xml.h:408
#define XML_LRM_ATTR_INTERVAL_MS
Definition: msg_xml.h:301
pe_working_set_t * data_set
xmlNode * input
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:529
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition: nvpair.c:726
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:650
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:323
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_resources
Definition: output.h:33
void pcmk__output_free(pcmk__output_t *out)
Definition: output.c:19
#define PCMK__OUTPUT_SPACER_IF(out_obj, cond)
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:29
const char * target
Definition: pcmk_fence.c:28
enum transition_status pcmk__simulate_transition(pe_working_set_t *data_set, cib_t *cib, GList *op_fail_list)
int pcmk_simulate(xmlNodePtr *xml, pe_working_set_t *data_set, pcmk_injections_t *injections, unsigned int flags, unsigned int section_opts, char *use_date, char *input_file, char *graph_file, char *dot_file)
Simulate a cluster's response to events.
#define STATUS_PATH_MAX
Definition: pcmk_simulate.c:25
void pcmk__profile_dir(const char *dir, long long repeat, pe_working_set_t *data_set, char *use_date)
int pcmk__simulate(pe_working_set_t *data_set, pcmk__output_t *out, pcmk_injections_t *injections, unsigned int flags, uint32_t section_opts, char *use_date, char *input_file, char *graph_file, char *dot_file)
int pcmk__out_prologue(pcmk__output_t **out, xmlNodePtr *xml)
pcmk__output_t * pcmk__new_logger(void)
void pcmk__register_lib_messages(pcmk__output_t *out)
Definition: pcmk_output.c:1920
void pcmk__out_epilogue(pcmk__output_t *out, xmlNodePtr *xml, int retval)
void pcmk__schedule_actions(xmlNode *cib, unsigned long long flags, pe_working_set_t *data_set)
@ pcmk__graph_action_confirmed
@ pcmk__graph_action_failed
crm_graph_t * pcmk__unpack_graph(xmlNode *xml_graph, const char *reference)
#define crm__set_graph_action_flags(action, flags_to_set)
void pcmk__log_graph(unsigned int log_level, crm_graph_t *graph)
void pcmk__free_graph(crm_graph_t *graph)
transition_status
@ transition_active
@ transition_complete
enum transition_status pcmk__execute_graph(crm_graph_t *graph)
void pcmk__update_graph(crm_graph_t *graph, crm_action_t *action)
void pcmk__set_graph_functions(crm_graph_functions_t *fns)
lrmd_event_data_t * pcmk__event_from_graph_action(xmlNode *resource, crm_action_t *action, int status, int rc, const char *exit_reason)
const char * pcmk__graph_status2text(enum transition_status state)
Data types for cluster status.
#define pe_rsc_managed
Definition: pe_types.h:257
#define pe_flag_maintenance_mode
Definition: pe_types.h:97
@ pe_order_none
Definition: pe_types.h:498
@ pe_order_load
Definition: pe_types.h:530
@ pe_link_dumped
Internal tracking for transition graph creation.
Definition: pe_types.h:486
#define pe_flag_show_scores
Definition: pe_types.h:134
@ pe_action_optional
Definition: pe_types.h:308
@ pe_action_runnable
Definition: pe_types.h:307
@ pe_action_dumped
Definition: pe_types.h:315
@ pe_action_pseudo
Definition: pe_types.h:306
#define pe_flag_no_compat
Definition: pe_types.h:132
#define pe_flag_sanitized
Definition: pe_types.h:121
#define pe_flag_show_utilization
Definition: pe_types.h:135
void pe__register_messages(pcmk__output_t *out)
Definition: pe_output.c:2923
#define pe__set_working_set_flags(working_set, flags_to_set)
Definition: internal.h:37
#define pe__set_action_flags(action, flags_to_set)
Definition: internal.h:61
int alphasort(const void *dirent1, const void *dirent2)
Function and executable result codes.
#define CRM_ASSERT(expr)
Definition: results.h:42
@ CRM_EX_OK
Success.
Definition: results.h:239
@ PCMK_OCF_OK
Success.
Definition: results.h:162
@ pcmk_rc_no_output
Definition: results.h:116
@ pcmk_rc_ok
Definition: results.h:146
@ pcmk_rc_error
Definition: results.h:142
@ pcmk_rc_dot_error
Definition: results.h:113
@ pcmk_rc_invalid_transition
Definition: results.h:111
@ pcmk_rc_graph_error
Definition: results.h:112
#define pcmk_ok
Definition: results.h:68
@ PCMK_EXEC_DONE
Action completed, result is known.
Definition: results.h:308
int pcmk_legacy2rc(int legacy_rc)
Definition: results.c:428
enum crm_exit_e crm_exit_t
void cleanup_calculations(pe_working_set_t *data_set)
Reset working set to default state without freeing it or constraints.
Definition: status.c:279
gboolean cluster_status(pe_working_set_t *data_set)
Definition: status.c:71
pe_resource_t * pe_find_resource(GList *rsc_list, const char *id_rh)
Definition: status.c:391
void pe_reset_working_set(pe_working_set_t *data_set)
Reset a working set to default state without freeing it.
Definition: status.c:338
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:563
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:931
@ 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
int(* remove)(cib_t *cib, const char *section, xmlNode *data, int call_options)
Definition: cib_types.h:113
int(* query)(cib_t *cib, const char *section, xmlNode **output_data, int call_options)
Definition: cib_types.h:92
int(* replace)(cib_t *cib, const char *section, xmlNode *data, int call_options)
Definition: cib_types.h:111
int(* modify)(cib_t *cib, const char *section, xmlNode *data, int call_options)
Definition: cib_types.h:107
cib_api_operations_t * cmds
Definition: cib_types.h:147
const char * op_type
Definition: lrmd.h:207
enum ocf_exitcode rc
Definition: lrmd.h:223
guint interval_ms
Definition: lrmd.h:216
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)
int(*) void(* err)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
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
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 * node_up
Definition: pacemaker.h:52
GList * op_inject
Definition: pacemaker.h:61
GList * op_fail
Definition: pacemaker.h:66
GList * ticket_standby
Definition: pacemaker.h:72
enum pe_action_flags flags
Definition: pe_types.h:433
enum pe_ordering type
Definition: pe_types.h:546
enum pe_link_state state
Definition: pe_types.h:547
pe_action_t * action
Definition: pe_types.h:548
int blocked_resources
Definition: pe_types.h:189
GList * actions
Definition: pe_types.h:171
xmlNode * input
Definition: pe_types.h:144
GList * resources
Definition: pe_types.h:165
xmlNode * graph
Definition: pe_types.h:183
int disabled_resources
Definition: pe_types.h:190
unsigned long long flags
Definition: pe_types.h:153
crm_time_t * now
Definition: pe_types.h:145
xmlNode * filename2xml(const char *filename)
Definition: xml.c:1045
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2794
gboolean cli_config_update(xmlNode **xml, int *best_version, gboolean to_logs)
Definition: schemas.c:1188
int write_xml_file(xmlNode *xml_node, const char *filename, gboolean compress)
Write XML to a file.
Definition: xml.c:1300
void free_xml(xmlNode *child)
Definition: xml.c:824
gboolean validate_xml(xmlNode *xml_blob, const char *validation, gboolean to_logs)
Definition: schemas.c:698
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:830
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:696