This source file includes following definitions.
- create_action_name
- print_cluster_status
- print_transition_summary
- reset
- write_sim_dotfile
- profile_file
- pcmk__profile_dir
- set_effective_date
- simulate_pseudo_action
- simulate_resource_action
- simulate_cluster_action
- simulate_fencing_action
- pcmk__simulate_transition
- pcmk__simulate
- pcmk_simulate
1
2
3
4
5
6
7
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>
14 #include <crm/pengine/pe_types.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
23 #include "libpacemaker_private.h"
24
25 static pcmk__output_t *out = NULL;
26 static cib_t *fake_cib = NULL;
27 static GList *fake_resource_list = NULL;
28 static GList *fake_op_fail_list = NULL;
29
30 static void set_effective_date(pe_working_set_t *data_set, bool print_original,
31 char *use_date);
32
33
34
35
36
37
38
39
40
41
42
43 static char *
44 create_action_name(pe_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, pe_action_pseudo)) {
55 action_host = "<none>";
56 }
57
58 if (pcmk__str_eq(action->task, RSC_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
71 if (pcmk__guint_from_hash(action->meta,
72 XML_LRM_ATTR_INTERVAL_MS, 0,
73 &interval_ms) != pcmk_rc_ok) {
74 interval_ms = 0;
75 }
76
77 if (pcmk__strcase_any_of(action->task, RSC_NOTIFY, RSC_NOTIFIED,
78 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, CRM_OP_FENCE, pcmk__str_casei)) {
100 const char *op = g_hash_table_lookup(action->meta, "stonith_action");
101
102 action_name = crm_strdup_printf("%s%s '%s' %s",
103 prefix, action->task, op, action_host);
104
105 } else if (action->rsc && action_host) {
106 action_name = crm_strdup_printf("%s%s %s",
107 prefix, action->uuid, action_host);
108
109 } else if (action_host) {
110 action_name = crm_strdup_printf("%s%s %s",
111 prefix, action->task, action_host);
112
113 } else {
114 action_name = crm_strdup_printf("%s", action->uuid);
115 }
116
117 if (verbose) {
118 char *with_id = crm_strdup_printf("%s (%d)", action_name, action->id);
119
120 free(action_name);
121 action_name = with_id;
122 }
123 return action_name;
124 }
125
126
127
128
129
130
131
132
133
134
135
136 static void
137 print_cluster_status(pe_working_set_t *data_set, uint32_t show_opts,
138 uint32_t section_opts, const char *title, bool print_spacer)
139 {
140 pcmk__output_t *out = data_set->priv;
141 GList *all = NULL;
142 crm_exit_t stonith_rc = 0;
143
144 section_opts |= pcmk_section_nodes | pcmk_section_resources;
145 show_opts |= pcmk_show_inactive_rscs | pcmk_show_failed_detail;
146
147 all = g_list_prepend(all, (gpointer) "*");
148
149 PCMK__OUTPUT_SPACER_IF(out, print_spacer);
150 out->begin_list(out, NULL, NULL, "%s", title);
151 out->message(out, "cluster-status", data_set, stonith_rc, NULL, false,
152 section_opts, show_opts, NULL, all, all);
153 out->end_list(out);
154
155 g_list_free(all);
156 }
157
158
159
160
161
162
163
164
165 static void
166 print_transition_summary(pe_working_set_t *data_set, bool print_spacer)
167 {
168 pcmk__output_t *out = data_set->priv;
169
170 PCMK__OUTPUT_SPACER_IF(out, print_spacer);
171 out->begin_list(out, NULL, NULL, "Transition Summary");
172 pcmk__output_actions(data_set);
173 out->end_list(out);
174 }
175
176
177
178
179
180
181
182
183
184
185
186 static void
187 reset(pe_working_set_t *data_set, xmlNodePtr input, pcmk__output_t *out,
188 char *use_date, unsigned int flags)
189 {
190 data_set->input = input;
191 data_set->priv = out;
192 set_effective_date(data_set, true, use_date);
193 if (pcmk_is_set(flags, pcmk_sim_sanitized)) {
194 pe__set_working_set_flags(data_set, pe_flag_sanitized);
195 }
196 if (pcmk_is_set(flags, pcmk_sim_show_scores)) {
197 pe__set_working_set_flags(data_set, pe_flag_show_scores);
198 }
199 if (pcmk_is_set(flags, pcmk_sim_show_utilization)) {
200 pe__set_working_set_flags(data_set, pe_flag_show_utilization);
201 }
202 }
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217 static int
218 write_sim_dotfile(pe_working_set_t *data_set, const char *dot_file,
219 bool all_actions, bool verbose)
220 {
221 GList *gIter = NULL;
222 FILE *dot_strm = fopen(dot_file, "w");
223
224 if (dot_strm == NULL) {
225 return errno;
226 }
227
228 fprintf(dot_strm, " digraph \"g\" {\n");
229 for (gIter = data_set->actions; gIter != NULL; gIter = gIter->next) {
230 pe_action_t *action = (pe_action_t *) gIter->data;
231 const char *style = "dashed";
232 const char *font = "black";
233 const char *color = "black";
234 char *action_name = create_action_name(action, verbose);
235
236 if (pcmk_is_set(action->flags, pe_action_pseudo)) {
237 font = "orange";
238 }
239
240 if (pcmk_is_set(action->flags, pe_action_dumped)) {
241 style = "bold";
242 color = "green";
243
244 } else if ((action->rsc != NULL)
245 && !pcmk_is_set(action->rsc->flags, pe_rsc_managed)) {
246 color = "red";
247 font = "purple";
248 if (!all_actions) {
249 goto do_not_write;
250 }
251
252 } else if (pcmk_is_set(action->flags, pe_action_optional)) {
253 color = "blue";
254 if (!all_actions) {
255 goto do_not_write;
256 }
257
258 } else {
259 color = "red";
260 CRM_LOG_ASSERT(!pcmk_is_set(action->flags, pe_action_runnable));
261 }
262
263 pe__set_action_flags(action, pe_action_dumped);
264 fprintf(dot_strm, "\"%s\" [ style=%s color=\"%s\" fontcolor=\"%s\"]\n",
265 action_name, style, color, font);
266 do_not_write:
267 free(action_name);
268 }
269
270 for (gIter = data_set->actions; gIter != NULL; gIter = gIter->next) {
271 pe_action_t *action = (pe_action_t *) gIter->data;
272
273 GList *gIter2 = NULL;
274
275 for (gIter2 = action->actions_before; gIter2 != NULL; gIter2 = gIter2->next) {
276 pe_action_wrapper_t *before = (pe_action_wrapper_t *) gIter2->data;
277
278 char *before_name = NULL;
279 char *after_name = NULL;
280 const char *style = "dashed";
281 bool optional = true;
282
283 if (before->state == pe_link_dumped) {
284 optional = false;
285 style = "bold";
286 } else if (before->type == pe_order_none) {
287 continue;
288 } else if (pcmk_is_set(before->action->flags, pe_action_dumped)
289 && pcmk_is_set(action->flags, pe_action_dumped)
290 && before->type != pe_order_load) {
291 optional = false;
292 }
293
294 if (all_actions || !optional) {
295 before_name = create_action_name(before->action, verbose);
296 after_name = create_action_name(action, verbose);
297 fprintf(dot_strm, "\"%s\" -> \"%s\" [ style = %s]\n",
298 before_name, after_name, style);
299 free(before_name);
300 free(after_name);
301 }
302 }
303 }
304
305 fprintf(dot_strm, "}\n");
306 fflush(dot_strm);
307 fclose(dot_strm);
308 return pcmk_rc_ok;
309 }
310
311
312
313
314
315
316
317
318
319
320
321
322
323 static void
324 profile_file(const char *xml_file, long long repeat, pe_working_set_t *data_set,
325 char *use_date)
326 {
327 pcmk__output_t *out = data_set->priv;
328 xmlNode *cib_object = NULL;
329 clock_t start = 0;
330 clock_t end;
331 unsigned long long data_set_flags = pe_flag_no_compat;
332
333 CRM_ASSERT(out != NULL);
334
335 cib_object = filename2xml(xml_file);
336 start = clock();
337
338 if (pcmk_find_cib_element(cib_object, XML_CIB_TAG_STATUS) == NULL) {
339 create_xml_node(cib_object, XML_CIB_TAG_STATUS);
340 }
341
342 if (cli_config_update(&cib_object, NULL, FALSE) == FALSE) {
343 free_xml(cib_object);
344 return;
345 }
346
347 if (validate_xml(cib_object, NULL, FALSE) != TRUE) {
348 free_xml(cib_object);
349 return;
350 }
351
352 if (pcmk_is_set(data_set->flags, pe_flag_show_scores)) {
353 data_set_flags |= pe_flag_show_scores;
354 }
355 if (pcmk_is_set(data_set->flags, pe_flag_show_utilization)) {
356 data_set_flags |= pe_flag_show_utilization;
357 }
358
359 for (int i = 0; i < repeat; ++i) {
360 xmlNode *input = (repeat == 1)? cib_object : copy_xml(cib_object);
361
362 data_set->input = input;
363 set_effective_date(data_set, false, use_date);
364 pcmk__schedule_actions(input, data_set_flags, data_set);
365 pe_reset_working_set(data_set);
366 }
367
368 end = clock();
369 out->message(out, "profile", xml_file, start, end);
370 }
371
372 void
373 pcmk__profile_dir(const char *dir, long long repeat, pe_working_set_t *data_set, char *use_date)
374 {
375 pcmk__output_t *out = data_set->priv;
376 struct dirent **namelist;
377
378 int file_num = scandir(dir, &namelist, 0, alphasort);
379
380 CRM_ASSERT(out != NULL);
381
382 if (file_num > 0) {
383 struct stat prop;
384 char buffer[FILENAME_MAX];
385
386 out->begin_list(out, NULL, NULL, "Timings");
387
388 while (file_num--) {
389 if ('.' == namelist[file_num]->d_name[0]) {
390 free(namelist[file_num]);
391 continue;
392
393 } else if (!pcmk__ends_with_ext(namelist[file_num]->d_name,
394 ".xml")) {
395 free(namelist[file_num]);
396 continue;
397 }
398 snprintf(buffer, sizeof(buffer), "%s/%s", dir, namelist[file_num]->d_name);
399 if (stat(buffer, &prop) == 0 && S_ISREG(prop.st_mode)) {
400 profile_file(buffer, repeat, data_set, use_date);
401 }
402 free(namelist[file_num]);
403 }
404 free(namelist);
405
406 out->end_list(out);
407 }
408 }
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423 static void
424 set_effective_date(pe_working_set_t *data_set, bool print_original,
425 char *use_date)
426 {
427 pcmk__output_t *out = data_set->priv;
428 time_t original_date = 0;
429
430 CRM_ASSERT(out != NULL);
431
432 crm_element_value_epoch(data_set->input, "execution-date", &original_date);
433
434 if (use_date) {
435 data_set->now = crm_time_new(use_date);
436 out->info(out, "Setting effective cluster time: %s", use_date);
437 crm_time_log(LOG_NOTICE, "Pretending 'now' is", data_set->now,
438 crm_time_log_date | crm_time_log_timeofday);
439
440 } else if (original_date) {
441
442 data_set->now = crm_time_new(NULL);
443 crm_time_set_timet(data_set->now, &original_date);
444
445 if (print_original) {
446 char *when = crm_time_as_string(data_set->now,
447 crm_time_log_date|crm_time_log_timeofday);
448
449 out->info(out, "Using the original execution date of: %s", when);
450 free(when);
451 }
452 }
453 }
454
455
456
457
458
459
460
461
462
463
464 static int
465 simulate_pseudo_action(pcmk__graph_t *graph, pcmk__graph_action_t *action)
466 {
467 const char *node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
468 const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY);
469
470 pcmk__set_graph_action_flags(action, pcmk__graph_action_confirmed);
471 out->message(out, "inject-pseudo-action", node, task);
472
473 pcmk__update_graph(graph, action);
474 return pcmk_rc_ok;
475 }
476
477
478
479
480
481
482
483
484
485
486 static int
487 simulate_resource_action(pcmk__graph_t *graph, pcmk__graph_action_t *action)
488 {
489 int rc;
490 lrmd_event_data_t *op = NULL;
491 int target_outcome = PCMK_OCF_OK;
492
493 const char *rtype = NULL;
494 const char *rclass = NULL;
495 const char *resource = NULL;
496 const char *rprovider = NULL;
497 const char *resource_config_name = NULL;
498 const char *operation = crm_element_value(action->xml, "operation");
499 const char *target_rc_s = crm_meta_value(action->params,
500 XML_ATTR_TE_TARGET_RC);
501
502 xmlNode *cib_node = NULL;
503 xmlNode *cib_resource = NULL;
504 xmlNode *action_rsc = first_named_child(action->xml, XML_CIB_TAG_RESOURCE);
505
506 char *node = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET);
507 char *uuid = NULL;
508 const char *router_node = crm_element_value(action->xml,
509 XML_LRM_ATTR_ROUTER_NODE);
510
511
512 if (pcmk__str_eq(operation, CRM_OP_REPROBE, pcmk__str_none)) {
513 crm_debug("No history injection for %s op on %s", operation, node);
514 goto done;
515 }
516
517 if (action_rsc == NULL) {
518 crm_log_xml_err(action->xml, "Bad");
519 free(node);
520 return EPROTO;
521 }
522
523
524
525
526
527
528 resource_config_name = crm_element_value(action_rsc, XML_ATTR_ID);
529 if (resource_config_name == NULL) {
530 crm_log_xml_err(action->xml, "No ID");
531 free(node);
532 return EPROTO;
533 }
534 resource = resource_config_name;
535 if (pe_find_resource(fake_resource_list, resource) == NULL) {
536 const char *longname = crm_element_value(action_rsc, XML_ATTR_ID_LONG);
537
538 if ((longname != NULL)
539 && (pe_find_resource(fake_resource_list, longname) != NULL)) {
540 resource = longname;
541 }
542 }
543
544
545 if (pcmk__strcase_any_of(operation, "delete", RSC_METADATA, NULL)) {
546 out->message(out, "inject-rsc-action", resource, operation, node,
547 (guint) 0);
548 goto done;
549 }
550
551 rclass = crm_element_value(action_rsc, XML_AGENT_ATTR_CLASS);
552 rtype = crm_element_value(action_rsc, XML_ATTR_TYPE);
553 rprovider = crm_element_value(action_rsc, XML_AGENT_ATTR_PROVIDER);
554
555 pcmk__scan_min_int(target_rc_s, &target_outcome, 0);
556
557 CRM_ASSERT(fake_cib->cmds->query(fake_cib, NULL, NULL,
558 cib_sync_call|cib_scope_local) == pcmk_ok);
559
560
561 uuid = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET_UUID);
562 cib_node = pcmk__inject_node(fake_cib, node,
563 ((router_node == NULL)? uuid: node));
564 free(uuid);
565 CRM_ASSERT(cib_node != NULL);
566
567
568 cib_resource = pcmk__inject_resource_history(out, cib_node, resource,
569 resource_config_name,
570 rclass, rtype, rprovider);
571 if (cib_resource == NULL) {
572 crm_err("Could not simulate action %d history for resource %s",
573 action->id, resource);
574 free(node);
575 free_xml(cib_node);
576 return EINVAL;
577 }
578
579
580 op = pcmk__event_from_graph_action(cib_resource, action, PCMK_EXEC_DONE,
581 target_outcome, "User-injected result");
582 out->message(out, "inject-rsc-action", resource, op->op_type, node,
583 op->interval_ms);
584
585
586 for (GList *iter = fake_op_fail_list; iter != NULL; iter = iter->next) {
587 char *spec = (char *) iter->data;
588 char *key = NULL;
589 const char *match_name = NULL;
590
591
592 key = crm_strdup_printf(PCMK__OP_FMT "@%s=", resource, op->op_type,
593 op->interval_ms, node);
594 if (strncasecmp(key, spec, strlen(key)) == 0) {
595 match_name = resource;
596 }
597 free(key);
598
599
600 if ((match_name == NULL)
601 && (strcmp(resource, resource_config_name) != 0)) {
602
603 key = crm_strdup_printf(PCMK__OP_FMT "@%s=", resource_config_name,
604 op->op_type, op->interval_ms, node);
605 if (strncasecmp(key, spec, strlen(key)) == 0) {
606 match_name = resource_config_name;
607 }
608 free(key);
609 }
610
611 if (match_name == NULL) {
612 continue;
613 }
614
615
616 rc = sscanf(spec, "%*[^=]=%d", (int *) &op->rc);
617 if (rc != 1) {
618 out->err(out, "Invalid failed operation '%s' "
619 "(result code must be integer)", spec);
620 continue;
621 }
622
623 out->info(out, "Pretending action %d failed with rc=%d",
624 action->id, op->rc);
625 pcmk__set_graph_action_flags(action, pcmk__graph_action_failed);
626 graph->abort_priority = INFINITY;
627 pcmk__inject_failcount(out, cib_node, match_name, op->op_type,
628 op->interval_ms, op->rc);
629 break;
630 }
631
632 pcmk__inject_action_result(cib_resource, op, target_outcome);
633 lrmd_free_event(op);
634 rc = fake_cib->cmds->modify(fake_cib, XML_CIB_TAG_STATUS, cib_node,
635 cib_sync_call|cib_scope_local);
636 CRM_ASSERT(rc == pcmk_ok);
637
638 done:
639 free(node);
640 free_xml(cib_node);
641 pcmk__set_graph_action_flags(action, pcmk__graph_action_confirmed);
642 pcmk__update_graph(graph, action);
643 return pcmk_rc_ok;
644 }
645
646
647
648
649
650
651
652
653
654
655 static int
656 simulate_cluster_action(pcmk__graph_t *graph, pcmk__graph_action_t *action)
657 {
658 const char *node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
659 const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
660 xmlNode *rsc = first_named_child(action->xml, XML_CIB_TAG_RESOURCE);
661
662 pcmk__set_graph_action_flags(action, pcmk__graph_action_confirmed);
663 out->message(out, "inject-cluster-action", node, task, rsc);
664 pcmk__update_graph(graph, action);
665 return pcmk_rc_ok;
666 }
667
668
669
670
671
672
673
674
675
676
677 static int
678 simulate_fencing_action(pcmk__graph_t *graph, pcmk__graph_action_t *action)
679 {
680 const char *op = crm_meta_value(action->params, "stonith_action");
681 char *target = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET);
682
683 out->message(out, "inject-fencing-action", target, op);
684
685 if (!pcmk__str_eq(op, "on", pcmk__str_casei)) {
686 int rc = pcmk_ok;
687 GString *xpath = g_string_sized_new(512);
688
689
690 xmlNode *cib_node = pcmk__inject_node_state_change(fake_cib, target,
691 false);
692
693 CRM_ASSERT(cib_node != NULL);
694 crm_xml_add(cib_node, XML_ATTR_ORIGIN, __func__);
695 rc = fake_cib->cmds->replace(fake_cib, XML_CIB_TAG_STATUS, cib_node,
696 cib_sync_call|cib_scope_local);
697 CRM_ASSERT(rc == pcmk_ok);
698
699
700 pcmk__g_strcat(xpath,
701 "//" XML_CIB_TAG_STATE
702 "[@" XML_ATTR_UNAME "='", target, "']/" XML_CIB_TAG_LRM,
703 NULL);
704 fake_cib->cmds->remove(fake_cib, (const char *) xpath->str, NULL,
705 cib_xpath|cib_sync_call|cib_scope_local);
706
707 g_string_truncate(xpath, 0);
708 pcmk__g_strcat(xpath,
709 "//" XML_CIB_TAG_STATE
710 "[@" XML_ATTR_UNAME "='", target, "']"
711 "/" XML_TAG_TRANSIENT_NODEATTRS, NULL);
712 fake_cib->cmds->remove(fake_cib, (const char *) xpath->str, NULL,
713 cib_xpath|cib_sync_call|cib_scope_local);
714
715 free_xml(cib_node);
716 g_string_free(xpath, TRUE);
717 }
718
719 pcmk__set_graph_action_flags(action, pcmk__graph_action_confirmed);
720 pcmk__update_graph(graph, action);
721 free(target);
722 return pcmk_rc_ok;
723 }
724
725 enum pcmk__graph_status
726 pcmk__simulate_transition(pe_working_set_t *data_set, cib_t *cib,
727 GList *op_fail_list)
728 {
729 pcmk__graph_t *transition = NULL;
730 enum pcmk__graph_status graph_rc;
731
732 pcmk__graph_functions_t simulation_fns = {
733 simulate_pseudo_action,
734 simulate_resource_action,
735 simulate_cluster_action,
736 simulate_fencing_action,
737 };
738
739 out = data_set->priv;
740
741 fake_cib = cib;
742 fake_op_fail_list = op_fail_list;
743
744 if (!out->is_quiet(out)) {
745 out->begin_list(out, NULL, NULL, "Executing Cluster Transition");
746 }
747
748 pcmk__set_graph_functions(&simulation_fns);
749 transition = pcmk__unpack_graph(data_set->graph, crm_system_name);
750 pcmk__log_graph(LOG_DEBUG, transition);
751
752 fake_resource_list = data_set->resources;
753 do {
754 graph_rc = pcmk__execute_graph(transition);
755 } while (graph_rc == pcmk__graph_active);
756 fake_resource_list = NULL;
757
758 if (graph_rc != pcmk__graph_complete) {
759 out->err(out, "Transition failed: %s",
760 pcmk__graph_status2text(graph_rc));
761 pcmk__log_graph(LOG_ERR, transition);
762 out->err(out, "An invalid transition was produced");
763 }
764 pcmk__free_graph(transition);
765
766 if (!out->is_quiet(out)) {
767
768 xmlNode *cib_object = NULL;
769 int rc = fake_cib->cmds->query(fake_cib, NULL, &cib_object,
770 cib_sync_call|cib_scope_local);
771
772 CRM_ASSERT(rc == pcmk_ok);
773 pe_reset_working_set(data_set);
774 data_set->input = cib_object;
775 out->end_list(out);
776 }
777 return graph_rc;
778 }
779
780 int
781 pcmk__simulate(pe_working_set_t *data_set, pcmk__output_t *out,
782 pcmk_injections_t *injections, unsigned int flags,
783 uint32_t section_opts, char *use_date, char *input_file,
784 char *graph_file, char *dot_file)
785 {
786 int printed = pcmk_rc_no_output;
787 int rc = pcmk_rc_ok;
788 xmlNodePtr input = NULL;
789 cib_t *cib = NULL;
790
791 rc = cib__signon_query(&cib, &input);
792 if (rc != pcmk_rc_ok) {
793 goto simulate_done;
794 }
795
796 reset(data_set, input, out, use_date, flags);
797 cluster_status(data_set);
798
799 if (!out->is_quiet(out)) {
800 if (pcmk_is_set(data_set->flags, pe_flag_maintenance_mode)) {
801 printed = out->message(out, "maint-mode", data_set->flags);
802 }
803
804 if (data_set->disabled_resources || data_set->blocked_resources) {
805 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
806 printed = out->info(out,
807 "%d of %d resource instances DISABLED and "
808 "%d BLOCKED from further action due to failure",
809 data_set->disabled_resources,
810 data_set->ninstances,
811 data_set->blocked_resources);
812 }
813
814
815
816
817 print_cluster_status(data_set,
818 pcmk_is_set(flags, pcmk_sim_show_pending)? pcmk_show_pending : 0,
819 section_opts, "Current cluster status",
820 (printed == pcmk_rc_ok));
821 printed = pcmk_rc_ok;
822 }
823
824
825 if ((injections->node_down != NULL)
826 || (injections->node_fail != NULL)
827 || (injections->node_up != NULL)
828 || (injections->op_inject != NULL)
829 || (injections->ticket_activate != NULL)
830 || (injections->ticket_grant != NULL)
831 || (injections->ticket_revoke != NULL)
832 || (injections->ticket_standby != NULL)
833 || (injections->watchdog != NULL)) {
834
835 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
836 pcmk__inject_scheduler_input(data_set, cib, injections);
837 printed = pcmk_rc_ok;
838
839 rc = cib->cmds->query(cib, NULL, &input, cib_sync_call);
840 if (rc != pcmk_rc_ok) {
841 rc = pcmk_legacy2rc(rc);
842 goto simulate_done;
843 }
844
845 cleanup_calculations(data_set);
846 reset(data_set, input, out, use_date, flags);
847 cluster_status(data_set);
848 }
849
850 if (input_file != NULL) {
851 rc = write_xml_file(input, input_file, FALSE);
852 if (rc < 0) {
853 rc = pcmk_legacy2rc(rc);
854 goto simulate_done;
855 }
856 }
857
858 if (pcmk_any_flags_set(flags, pcmk_sim_process | pcmk_sim_simulate)) {
859 pcmk__output_t *logger_out = NULL;
860 unsigned long long data_set_flags = pe_flag_no_compat;
861
862 if (pcmk_is_set(data_set->flags, pe_flag_show_scores)) {
863 data_set_flags |= pe_flag_show_scores;
864 }
865 if (pcmk_is_set(data_set->flags, pe_flag_show_utilization)) {
866 data_set_flags |= pe_flag_show_utilization;
867 }
868
869 if (pcmk_all_flags_set(data_set->flags,
870 pe_flag_show_scores|pe_flag_show_utilization)) {
871 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
872 out->begin_list(out, NULL, NULL,
873 "Allocation Scores and Utilization Information");
874 printed = pcmk_rc_ok;
875
876 } else if (pcmk_is_set(data_set->flags, pe_flag_show_scores)) {
877 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
878 out->begin_list(out, NULL, NULL, "Allocation Scores");
879 printed = pcmk_rc_ok;
880
881 } else if (pcmk_is_set(data_set->flags, pe_flag_show_utilization)) {
882 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
883 out->begin_list(out, NULL, NULL, "Utilization Information");
884 printed = pcmk_rc_ok;
885
886 } else {
887 rc = pcmk__log_output_new(&logger_out);
888 if (rc != pcmk_rc_ok) {
889 goto simulate_done;
890 }
891 pe__register_messages(logger_out);
892 pcmk__register_lib_messages(logger_out);
893 data_set->priv = logger_out;
894 }
895
896 pcmk__schedule_actions(input, data_set_flags, data_set);
897
898 if (logger_out == NULL) {
899 out->end_list(out);
900 } else {
901 logger_out->finish(logger_out, CRM_EX_OK, true, NULL);
902 pcmk__output_free(logger_out);
903 data_set->priv = out;
904 }
905
906 input = NULL;
907
908 if (graph_file != NULL) {
909 rc = write_xml_file(data_set->graph, graph_file, FALSE);
910 if (rc < 0) {
911 rc = pcmk_rc_graph_error;
912 goto simulate_done;
913 }
914 }
915
916 if (dot_file != NULL) {
917 rc = write_sim_dotfile(data_set, dot_file,
918 pcmk_is_set(flags, pcmk_sim_all_actions),
919 pcmk_is_set(flags, pcmk_sim_verbose));
920 if (rc != pcmk_rc_ok) {
921 rc = pcmk_rc_dot_error;
922 goto simulate_done;
923 }
924 }
925
926 if (!out->is_quiet(out)) {
927 print_transition_summary(data_set, printed == pcmk_rc_ok);
928 }
929 }
930
931 rc = pcmk_rc_ok;
932
933 if (!pcmk_is_set(flags, pcmk_sim_simulate)) {
934 goto simulate_done;
935 }
936
937 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
938 if (pcmk__simulate_transition(data_set, cib,
939 injections->op_fail) != pcmk__graph_complete) {
940 rc = pcmk_rc_invalid_transition;
941 }
942
943 if (out->is_quiet(out)) {
944 goto simulate_done;
945 }
946
947 set_effective_date(data_set, true, use_date);
948
949 if (pcmk_is_set(flags, pcmk_sim_show_scores)) {
950 pe__set_working_set_flags(data_set, pe_flag_show_scores);
951 }
952 if (pcmk_is_set(flags, pcmk_sim_show_utilization)) {
953 pe__set_working_set_flags(data_set, pe_flag_show_utilization);
954 }
955
956 cluster_status(data_set);
957 print_cluster_status(data_set, 0, section_opts, "Revised Cluster Status",
958 true);
959
960 simulate_done:
961 cib__clean_up_connection(&cib);
962 return rc;
963 }
964
965 int
966 pcmk_simulate(xmlNodePtr *xml, pe_working_set_t *data_set,
967 pcmk_injections_t *injections, unsigned int flags,
968 unsigned int section_opts, char *use_date, char *input_file,
969 char *graph_file, char *dot_file)
970 {
971 pcmk__output_t *out = NULL;
972 int rc = pcmk_rc_ok;
973
974 rc = pcmk__xml_output_new(&out, xml);
975 if (rc != pcmk_rc_ok) {
976 return rc;
977 }
978
979 pe__register_messages(out);
980 pcmk__register_lib_messages(out);
981
982 rc = pcmk__simulate(data_set, out, injections, flags, section_opts,
983 use_date, input_file, graph_file, dot_file);
984 pcmk__xml_output_finish(out, xml);
985 return rc;
986 }