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 const GList *fake_op_fail_list = NULL;
29
30 static void set_effective_date(pe_working_set_t *data_set, bool print_original,
31 const char *use_date);
32
33
34
35
36
37
38
39
40
41
42
43 static char *
44 create_action_name(const 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 enum pcmk_pacemakerd_state state = pcmk_pacemakerd_state_invalid;
144
145 section_opts |= pcmk_section_nodes | pcmk_section_resources;
146 show_opts |= pcmk_show_inactive_rscs | pcmk_show_failed_detail;
147
148 all = g_list_prepend(all, (gpointer) "*");
149
150 PCMK__OUTPUT_SPACER_IF(out, print_spacer);
151 out->begin_list(out, NULL, NULL, "%s", title);
152 out->message(out, "cluster-status",
153 data_set, state, stonith_rc, NULL,
154 false, section_opts, show_opts, NULL, all, all);
155 out->end_list(out);
156
157 g_list_free(all);
158 }
159
160
161
162
163
164
165
166
167 static void
168 print_transition_summary(pe_working_set_t *data_set, bool print_spacer)
169 {
170 pcmk__output_t *out = data_set->priv;
171
172 PCMK__OUTPUT_SPACER_IF(out, print_spacer);
173 out->begin_list(out, NULL, NULL, "Transition Summary");
174 pcmk__output_actions(data_set);
175 out->end_list(out);
176 }
177
178
179
180
181
182
183
184
185
186
187
188 static void
189 reset(pe_working_set_t *data_set, xmlNodePtr input, pcmk__output_t *out,
190 const char *use_date, unsigned int flags)
191 {
192 data_set->input = input;
193 data_set->priv = out;
194 set_effective_date(data_set, true, use_date);
195 if (pcmk_is_set(flags, pcmk_sim_sanitized)) {
196 pe__set_working_set_flags(data_set, pe_flag_sanitized);
197 }
198 if (pcmk_is_set(flags, pcmk_sim_show_scores)) {
199 pe__set_working_set_flags(data_set, pe_flag_show_scores);
200 }
201 if (pcmk_is_set(flags, pcmk_sim_show_utilization)) {
202 pe__set_working_set_flags(data_set, pe_flag_show_utilization);
203 }
204 }
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219 static int
220 write_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";
262 CRM_LOG_ASSERT(!pcmk_is_set(action->flags, pe_action_runnable));
263 }
264
265 pe__set_action_flags(action, pe_action_dumped);
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)
291 && pcmk_is_set(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
313
314
315
316
317
318
319
320
321
322
323
324
325 static void
326 profile_file(const char *xml_file, long long repeat, pe_working_set_t *data_set,
327 const char *use_date)
328 {
329 pcmk__output_t *out = data_set->priv;
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) {
341 create_xml_node(cib_object, XML_CIB_TAG_STATUS);
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
354 if (pcmk_is_set(data_set->flags, pe_flag_show_scores)) {
355 data_set_flags |= pe_flag_show_scores;
356 }
357 if (pcmk_is_set(data_set->flags, pe_flag_show_utilization)) {
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
364 data_set->input = input;
365 set_effective_date(data_set, false, use_date);
366 pcmk__schedule_actions(input, data_set_flags, data_set);
367 pe_reset_working_set(data_set);
368 }
369
370 end = clock();
371 out->message(out, "profile", xml_file, start, end);
372 }
373
374 void
375 pcmk__profile_dir(const char *dir, long long repeat, pe_working_set_t *data_set,
376 const char *use_date)
377 {
378 pcmk__output_t *out = data_set->priv;
379 struct dirent **namelist;
380
381 int file_num = scandir(dir, &namelist, 0, alphasort);
382
383 CRM_ASSERT(out != NULL);
384
385 if (file_num > 0) {
386 struct stat prop;
387 char buffer[FILENAME_MAX];
388
389 out->begin_list(out, NULL, NULL, "Timings");
390
391 while (file_num--) {
392 if ('.' == namelist[file_num]->d_name[0]) {
393 free(namelist[file_num]);
394 continue;
395
396 } else if (!pcmk__ends_with_ext(namelist[file_num]->d_name,
397 ".xml")) {
398 free(namelist[file_num]);
399 continue;
400 }
401 snprintf(buffer, sizeof(buffer), "%s/%s", dir, namelist[file_num]->d_name);
402 if (stat(buffer, &prop) == 0 && S_ISREG(prop.st_mode)) {
403 profile_file(buffer, repeat, data_set, use_date);
404 }
405 free(namelist[file_num]);
406 }
407 free(namelist);
408
409 out->end_list(out);
410 }
411 }
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426 static void
427 set_effective_date(pe_working_set_t *data_set, bool print_original,
428 const char *use_date)
429 {
430 pcmk__output_t *out = data_set->priv;
431 time_t original_date = 0;
432
433 CRM_ASSERT(out != NULL);
434
435 crm_element_value_epoch(data_set->input, "execution-date", &original_date);
436
437 if (use_date) {
438 data_set->now = crm_time_new(use_date);
439 out->info(out, "Setting effective cluster time: %s", use_date);
440 crm_time_log(LOG_NOTICE, "Pretending 'now' is", data_set->now,
441 crm_time_log_date | crm_time_log_timeofday);
442
443 } else if (original_date != 0) {
444 data_set->now = pcmk__copy_timet(original_date);
445
446 if (print_original) {
447 char *when = crm_time_as_string(data_set->now,
448 crm_time_log_date|crm_time_log_timeofday);
449
450 out->info(out, "Using the original execution date of: %s", when);
451 free(when);
452 }
453 }
454 }
455
456
457
458
459
460
461
462
463
464
465 static int
466 simulate_pseudo_action(pcmk__graph_t *graph, pcmk__graph_action_t *action)
467 {
468 const char *node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
469 const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY);
470
471 pcmk__set_graph_action_flags(action, pcmk__graph_action_confirmed);
472 out->message(out, "inject-pseudo-action", node, task);
473
474 pcmk__update_graph(graph, action);
475 return pcmk_rc_ok;
476 }
477
478
479
480
481
482
483
484
485
486
487 static int
488 simulate_resource_action(pcmk__graph_t *graph, pcmk__graph_action_t *action)
489 {
490 int rc;
491 lrmd_event_data_t *op = NULL;
492 int target_outcome = PCMK_OCF_OK;
493
494 const char *rtype = NULL;
495 const char *rclass = NULL;
496 const char *resource = NULL;
497 const char *rprovider = NULL;
498 const char *resource_config_name = NULL;
499 const char *operation = crm_element_value(action->xml, "operation");
500 const char *target_rc_s = crm_meta_value(action->params,
501 XML_ATTR_TE_TARGET_RC);
502
503 xmlNode *cib_node = NULL;
504 xmlNode *cib_resource = NULL;
505 xmlNode *action_rsc = first_named_child(action->xml, XML_CIB_TAG_RESOURCE);
506
507 char *node = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET);
508 char *uuid = NULL;
509 const char *router_node = crm_element_value(action->xml,
510 XML_LRM_ATTR_ROUTER_NODE);
511
512
513 if (pcmk__str_eq(operation, CRM_OP_REPROBE, pcmk__str_none)) {
514 crm_debug("No history injection for %s op on %s", operation, node);
515 goto done;
516 }
517
518 if (action_rsc == NULL) {
519 crm_log_xml_err(action->xml, "Bad");
520 free(node);
521 return EPROTO;
522 }
523
524
525
526
527
528
529 resource_config_name = crm_element_value(action_rsc, XML_ATTR_ID);
530 if (resource_config_name == NULL) {
531 crm_log_xml_err(action->xml, "No ID");
532 free(node);
533 return EPROTO;
534 }
535 resource = resource_config_name;
536 if (pe_find_resource(fake_resource_list, resource) == NULL) {
537 const char *longname = crm_element_value(action_rsc, XML_ATTR_ID_LONG);
538
539 if ((longname != NULL)
540 && (pe_find_resource(fake_resource_list, longname) != NULL)) {
541 resource = longname;
542 }
543 }
544
545
546 if (pcmk__strcase_any_of(operation, "delete", RSC_METADATA, NULL)) {
547 out->message(out, "inject-rsc-action", resource, operation, node,
548 (guint) 0);
549 goto done;
550 }
551
552 rclass = crm_element_value(action_rsc, XML_AGENT_ATTR_CLASS);
553 rtype = crm_element_value(action_rsc, XML_ATTR_TYPE);
554 rprovider = crm_element_value(action_rsc, XML_AGENT_ATTR_PROVIDER);
555
556 pcmk__scan_min_int(target_rc_s, &target_outcome, 0);
557
558 CRM_ASSERT(fake_cib->cmds->query(fake_cib, NULL, NULL,
559 cib_sync_call|cib_scope_local) == pcmk_ok);
560
561
562 uuid = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET_UUID);
563 cib_node = pcmk__inject_node(fake_cib, node,
564 ((router_node == NULL)? uuid: node));
565 free(uuid);
566 CRM_ASSERT(cib_node != NULL);
567
568
569 cib_resource = pcmk__inject_resource_history(out, cib_node, resource,
570 resource_config_name,
571 rclass, rtype, rprovider);
572 if (cib_resource == NULL) {
573 crm_err("Could not simulate action %d history for resource %s",
574 action->id, resource);
575 free(node);
576 free_xml(cib_node);
577 return EINVAL;
578 }
579
580
581 op = pcmk__event_from_graph_action(cib_resource, action, PCMK_EXEC_DONE,
582 target_outcome, "User-injected result");
583 out->message(out, "inject-rsc-action", resource, op->op_type, node,
584 op->interval_ms);
585
586
587 for (const GList *iter = fake_op_fail_list;
588 iter != NULL; iter = iter->next) {
589 const char *spec = (const char *) iter->data;
590 char *key = NULL;
591 const char *match_name = NULL;
592
593
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
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;
615 }
616
617
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;
623 }
624
625 out->info(out, "Pretending action %d failed with rc=%d",
626 action->id, op->rc);
627 pcmk__set_graph_action_flags(action, pcmk__graph_action_failed);
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,
637 cib_sync_call|cib_scope_local);
638 CRM_ASSERT(rc == pcmk_ok);
639
640 done:
641 free(node);
642 free_xml(cib_node);
643 pcmk__set_graph_action_flags(action, pcmk__graph_action_confirmed);
644 pcmk__update_graph(graph, action);
645 return pcmk_rc_ok;
646 }
647
648
649
650
651
652
653
654
655
656
657 static int
658 simulate_cluster_action(pcmk__graph_t *graph, pcmk__graph_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
664 pcmk__set_graph_action_flags(action, pcmk__graph_action_confirmed);
665 out->message(out, "inject-cluster-action", node, task, rsc);
666 pcmk__update_graph(graph, action);
667 return pcmk_rc_ok;
668 }
669
670
671
672
673
674
675
676
677
678
679 static int
680 simulate_fencing_action(pcmk__graph_t *graph, pcmk__graph_action_t *action)
681 {
682 const char *op = crm_meta_value(action->params, "stonith_action");
683 char *target = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET);
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 GString *xpath = g_string_sized_new(512);
690
691
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,
698 cib_sync_call|cib_scope_local);
699 CRM_ASSERT(rc == pcmk_ok);
700
701
702 pcmk__g_strcat(xpath,
703 "//" XML_CIB_TAG_STATE
704 "[@" XML_ATTR_UNAME "='", target, "']/" XML_CIB_TAG_LRM,
705 NULL);
706 fake_cib->cmds->remove(fake_cib, (const char *) xpath->str, NULL,
707 cib_xpath|cib_sync_call|cib_scope_local);
708
709 g_string_truncate(xpath, 0);
710 pcmk__g_strcat(xpath,
711 "//" XML_CIB_TAG_STATE
712 "[@" XML_ATTR_UNAME "='", target, "']"
713 "/" XML_TAG_TRANSIENT_NODEATTRS, NULL);
714 fake_cib->cmds->remove(fake_cib, (const char *) xpath->str, NULL,
715 cib_xpath|cib_sync_call|cib_scope_local);
716
717 free_xml(cib_node);
718 g_string_free(xpath, TRUE);
719 }
720
721 pcmk__set_graph_action_flags(action, pcmk__graph_action_confirmed);
722 pcmk__update_graph(graph, action);
723 free(target);
724 return pcmk_rc_ok;
725 }
726
727 enum pcmk__graph_status
728 pcmk__simulate_transition(pe_working_set_t *data_set, cib_t *cib,
729 const GList *op_fail_list)
730 {
731 pcmk__graph_t *transition = NULL;
732 enum pcmk__graph_status graph_rc;
733
734 pcmk__graph_functions_t simulation_fns = {
735 simulate_pseudo_action,
736 simulate_resource_action,
737 simulate_cluster_action,
738 simulate_fencing_action,
739 };
740
741 out = data_set->priv;
742
743 fake_cib = cib;
744 fake_op_fail_list = op_fail_list;
745
746 if (!out->is_quiet(out)) {
747 out->begin_list(out, NULL, NULL, "Executing Cluster Transition");
748 }
749
750 pcmk__set_graph_functions(&simulation_fns);
751 transition = pcmk__unpack_graph(data_set->graph, crm_system_name);
752 pcmk__log_graph(LOG_DEBUG, transition);
753
754 fake_resource_list = data_set->resources;
755 do {
756 graph_rc = pcmk__execute_graph(transition);
757 } while (graph_rc == pcmk__graph_active);
758 fake_resource_list = NULL;
759
760 if (graph_rc != pcmk__graph_complete) {
761 out->err(out, "Transition failed: %s",
762 pcmk__graph_status2text(graph_rc));
763 pcmk__log_graph(LOG_ERR, transition);
764 out->err(out, "An invalid transition was produced");
765 }
766 pcmk__free_graph(transition);
767
768 if (!out->is_quiet(out)) {
769
770 xmlNode *cib_object = NULL;
771 int rc = fake_cib->cmds->query(fake_cib, NULL, &cib_object,
772 cib_sync_call|cib_scope_local);
773
774 CRM_ASSERT(rc == pcmk_ok);
775 pe_reset_working_set(data_set);
776 data_set->input = cib_object;
777 out->end_list(out);
778 }
779 return graph_rc;
780 }
781
782 int
783 pcmk__simulate(pe_working_set_t *data_set, pcmk__output_t *out,
784 const pcmk_injections_t *injections, unsigned int flags,
785 uint32_t section_opts, const char *use_date,
786 const char *input_file, const char *graph_file,
787 const char *dot_file)
788 {
789 int printed = pcmk_rc_no_output;
790 int rc = pcmk_rc_ok;
791 xmlNodePtr input = NULL;
792 cib_t *cib = NULL;
793
794 rc = cib__signon_query(out, &cib, &input);
795 if (rc != pcmk_rc_ok) {
796 goto simulate_done;
797 }
798
799 reset(data_set, input, out, use_date, flags);
800 cluster_status(data_set);
801
802 if ((cib->variant == cib_native)
803 && pcmk_is_set(section_opts, pcmk_section_times)) {
804 if (pcmk__our_nodename == NULL) {
805
806 pcmk__query_node_name(out, 0, &pcmk__our_nodename, 0);
807 }
808 data_set->localhost = pcmk__our_nodename;
809 }
810
811 if (!out->is_quiet(out)) {
812 if (pcmk_is_set(data_set->flags, pe_flag_maintenance_mode)) {
813 printed = out->message(out, "maint-mode", data_set->flags);
814 }
815
816 if (data_set->disabled_resources || data_set->blocked_resources) {
817 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
818 printed = out->info(out,
819 "%d of %d resource instances DISABLED and "
820 "%d BLOCKED from further action due to failure",
821 data_set->disabled_resources,
822 data_set->ninstances,
823 data_set->blocked_resources);
824 }
825
826
827
828
829 print_cluster_status(data_set,
830 pcmk_is_set(flags, pcmk_sim_show_pending)? pcmk_show_pending : 0,
831 section_opts, "Current cluster status",
832 (printed == pcmk_rc_ok));
833 printed = pcmk_rc_ok;
834 }
835
836
837 if ((injections->node_down != NULL)
838 || (injections->node_fail != NULL)
839 || (injections->node_up != NULL)
840 || (injections->op_inject != NULL)
841 || (injections->ticket_activate != NULL)
842 || (injections->ticket_grant != NULL)
843 || (injections->ticket_revoke != NULL)
844 || (injections->ticket_standby != NULL)
845 || (injections->watchdog != NULL)) {
846
847 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
848 pcmk__inject_scheduler_input(data_set, cib, injections);
849 printed = pcmk_rc_ok;
850
851 rc = cib->cmds->query(cib, NULL, &input, cib_sync_call);
852 if (rc != pcmk_rc_ok) {
853 rc = pcmk_legacy2rc(rc);
854 goto simulate_done;
855 }
856
857 cleanup_calculations(data_set);
858 reset(data_set, input, out, use_date, flags);
859 cluster_status(data_set);
860 }
861
862 if (input_file != NULL) {
863 rc = write_xml_file(input, input_file, FALSE);
864 if (rc < 0) {
865 rc = pcmk_legacy2rc(rc);
866 goto simulate_done;
867 }
868 }
869
870 if (pcmk_any_flags_set(flags, pcmk_sim_process | pcmk_sim_simulate)) {
871 pcmk__output_t *logger_out = NULL;
872 unsigned long long data_set_flags = pe_flag_no_compat;
873
874 if (pcmk_is_set(data_set->flags, pe_flag_show_scores)) {
875 data_set_flags |= pe_flag_show_scores;
876 }
877 if (pcmk_is_set(data_set->flags, pe_flag_show_utilization)) {
878 data_set_flags |= pe_flag_show_utilization;
879 }
880
881 if (pcmk_all_flags_set(data_set->flags,
882 pe_flag_show_scores|pe_flag_show_utilization)) {
883 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
884 out->begin_list(out, NULL, NULL,
885 "Allocation Scores and Utilization Information");
886 printed = pcmk_rc_ok;
887
888 } else if (pcmk_is_set(data_set->flags, pe_flag_show_scores)) {
889 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
890 out->begin_list(out, NULL, NULL, "Allocation Scores");
891 printed = pcmk_rc_ok;
892
893 } else if (pcmk_is_set(data_set->flags, pe_flag_show_utilization)) {
894 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
895 out->begin_list(out, NULL, NULL, "Utilization Information");
896 printed = pcmk_rc_ok;
897
898 } else {
899 rc = pcmk__log_output_new(&logger_out);
900 if (rc != pcmk_rc_ok) {
901 goto simulate_done;
902 }
903 pe__register_messages(logger_out);
904 pcmk__register_lib_messages(logger_out);
905 data_set->priv = logger_out;
906 }
907
908 pcmk__schedule_actions(input, data_set_flags, data_set);
909
910 if (logger_out == NULL) {
911 out->end_list(out);
912 } else {
913 logger_out->finish(logger_out, CRM_EX_OK, true, NULL);
914 pcmk__output_free(logger_out);
915 data_set->priv = out;
916 }
917
918 input = NULL;
919
920 if (graph_file != NULL) {
921 rc = write_xml_file(data_set->graph, graph_file, FALSE);
922 if (rc < 0) {
923 rc = pcmk_rc_graph_error;
924 goto simulate_done;
925 }
926 }
927
928 if (dot_file != NULL) {
929 rc = write_sim_dotfile(data_set, dot_file,
930 pcmk_is_set(flags, pcmk_sim_all_actions),
931 pcmk_is_set(flags, pcmk_sim_verbose));
932 if (rc != pcmk_rc_ok) {
933 rc = pcmk_rc_dot_error;
934 goto simulate_done;
935 }
936 }
937
938 if (!out->is_quiet(out)) {
939 print_transition_summary(data_set, printed == pcmk_rc_ok);
940 }
941 }
942
943 rc = pcmk_rc_ok;
944
945 if (!pcmk_is_set(flags, pcmk_sim_simulate)) {
946 goto simulate_done;
947 }
948
949 PCMK__OUTPUT_SPACER_IF(out, printed == pcmk_rc_ok);
950 if (pcmk__simulate_transition(data_set, cib,
951 injections->op_fail) != pcmk__graph_complete) {
952 rc = pcmk_rc_invalid_transition;
953 }
954
955 if (out->is_quiet(out)) {
956 goto simulate_done;
957 }
958
959 set_effective_date(data_set, true, use_date);
960
961 if (pcmk_is_set(flags, pcmk_sim_show_scores)) {
962 pe__set_working_set_flags(data_set, pe_flag_show_scores);
963 }
964 if (pcmk_is_set(flags, pcmk_sim_show_utilization)) {
965 pe__set_working_set_flags(data_set, pe_flag_show_utilization);
966 }
967
968 cluster_status(data_set);
969 print_cluster_status(data_set, 0, section_opts, "Revised Cluster Status",
970 true);
971
972 simulate_done:
973 cib__clean_up_connection(&cib);
974 return rc;
975 }
976
977 int
978 pcmk_simulate(xmlNodePtr *xml, pe_working_set_t *data_set,
979 const pcmk_injections_t *injections, unsigned int flags,
980 unsigned int section_opts, const char *use_date,
981 const char *input_file, const char *graph_file,
982 const char *dot_file)
983 {
984 pcmk__output_t *out = NULL;
985 int rc = pcmk_rc_ok;
986
987 rc = pcmk__xml_output_new(&out, xml);
988 if (rc != pcmk_rc_ok) {
989 return rc;
990 }
991
992 pe__register_messages(out);
993 pcmk__register_lib_messages(out);
994
995 rc = pcmk__simulate(data_set, out, injections, flags, section_opts,
996 use_date, input_file, graph_file, dot_file);
997 pcmk__xml_output_finish(out, xml);
998 return rc;
999 }