root/tools/crm_simulate.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. all_actions_cb
  2. attrs_cb
  3. failcounts_cb
  4. in_place_cb
  5. live_check_cb
  6. node_down_cb
  7. node_fail_cb
  8. node_up_cb
  9. op_fail_cb
  10. op_inject_cb
  11. pending_cb
  12. process_cb
  13. quorum_cb
  14. save_dotfile_cb
  15. save_graph_cb
  16. show_scores_cb
  17. simulate_cb
  18. ticket_activate_cb
  19. ticket_grant_cb
  20. ticket_revoke_cb
  21. ticket_standby_cb
  22. utilization_cb
  23. watchdog_cb
  24. xml_file_cb
  25. xml_pipe_cb
  26. setup_input
  27. build_arg_context
  28. main

   1 /*
   2  * Copyright 2009-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 General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <stdint.h>
  13 #include <stdio.h>
  14 #include <unistd.h>
  15 #include <stdlib.h>
  16 #include <time.h>
  17 
  18 #include <sys/stat.h>
  19 #include <sys/param.h>
  20 #include <sys/types.h>
  21 #include <dirent.h>
  22 
  23 #include <crm/crm.h>
  24 #include <crm/cib.h>
  25 #include <crm/cib/internal.h>
  26 #include <crm/common/cmdline_internal.h>
  27 #include <crm/common/output_internal.h>
  28 #include <crm/common/output.h>
  29 #include <crm/common/util.h>
  30 #include <crm/common/iso8601.h>
  31 #include <crm/pengine/status.h>
  32 #include <crm/pengine/internal.h>
  33 #include <pacemaker-internal.h>
  34 #include <pacemaker.h>
  35 
  36 #define SUMMARY "crm_simulate - simulate a Pacemaker cluster's response to events"
  37 
  38 struct {
  39     char *dot_file;
  40     char *graph_file;
  41     gchar *input_file;
  42     pcmk_injections_t *injections;
  43     unsigned int flags;
  44     gchar *output_file;
  45     long long repeat;
  46     gboolean store;
  47     gchar *test_dir;
  48     char *use_date;
  49     char *xml_file;
  50 } options = {
  51     .flags = pcmk_sim_show_pending | pcmk_sim_sanitized,
  52     .repeat = 1
  53 };
  54 
  55 uint32_t section_opts = 0;
  56 char *temp_shadow = NULL;
  57 crm_exit_t exit_code = CRM_EX_OK;
  58 
  59 #define INDENT "                                   "
  60 
  61 static pcmk__supported_format_t formats[] = {
  62     PCMK__SUPPORTED_FORMAT_NONE,
  63     PCMK__SUPPORTED_FORMAT_TEXT,
  64     PCMK__SUPPORTED_FORMAT_XML,
  65     { NULL, NULL, NULL }
  66 };
  67 
  68 static gboolean
  69 all_actions_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
  70     options.flags |= pcmk_sim_all_actions;
  71     return TRUE;
  72 }
  73 
  74 static gboolean
  75 attrs_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
  76     section_opts |= pcmk_section_attributes;
  77     return TRUE;
  78 }
  79 
  80 static gboolean
  81 failcounts_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
  82     section_opts |= pcmk_section_failcounts | pcmk_section_failures;
  83     return TRUE;
  84 }
  85 
  86 static gboolean
  87 in_place_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
  88     options.store = TRUE;
  89     options.flags |= pcmk_sim_process | pcmk_sim_simulate;
  90     return TRUE;
  91 }
  92 
  93 static gboolean
  94 live_check_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
  95     if (options.xml_file) {
  96         free(options.xml_file);
  97     }
  98 
  99     options.xml_file = NULL;
 100     options.flags &= ~pcmk_sim_sanitized;
 101     return TRUE;
 102 }
 103 
 104 static gboolean
 105 node_down_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 106     options.injections->node_down = g_list_append(options.injections->node_down, g_strdup(optarg));
 107     return TRUE;
 108 }
 109 
 110 static gboolean
 111 node_fail_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 112     options.injections->node_fail = g_list_append(options.injections->node_fail, g_strdup(optarg));
 113     return TRUE;
 114 }
 115 
 116 static gboolean
 117 node_up_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 118     pcmk__simulate_node_config = true;
 119     options.injections->node_up = g_list_append(options.injections->node_up, g_strdup(optarg));
 120     return TRUE;
 121 }
 122 
 123 static gboolean
 124 op_fail_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 125     options.flags |= pcmk_sim_process | pcmk_sim_simulate;
 126     options.injections->op_fail = g_list_append(options.injections->op_fail, g_strdup(optarg));
 127     return TRUE;
 128 }
 129 
 130 static gboolean
 131 op_inject_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 132     options.injections->op_inject = g_list_append(options.injections->op_inject, g_strdup(optarg));
 133     return TRUE;
 134 }
 135 
 136 static gboolean
 137 pending_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 138     options.flags |= pcmk_sim_show_pending;
 139     return TRUE;
 140 }
 141 
 142 static gboolean
 143 process_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 144     options.flags |= pcmk_sim_process;
 145     return TRUE;
 146 }
 147 
 148 static gboolean
 149 quorum_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 150     pcmk__str_update(&options.injections->quorum, optarg);
 151     return TRUE;
 152 }
 153 
 154 static gboolean
 155 save_dotfile_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 156     options.flags |= pcmk_sim_process;
 157     pcmk__str_update(&options.dot_file, optarg);
 158     return TRUE;
 159 }
 160 
 161 static gboolean
 162 save_graph_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 163     options.flags |= pcmk_sim_process;
 164     pcmk__str_update(&options.graph_file, optarg);
 165     return TRUE;
 166 }
 167 
 168 static gboolean
 169 show_scores_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 170     options.flags |= pcmk_sim_process | pcmk_sim_show_scores;
 171     return TRUE;
 172 }
 173 
 174 static gboolean
 175 simulate_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 176     options.flags |= pcmk_sim_process | pcmk_sim_simulate;
 177     return TRUE;
 178 }
 179 
 180 static gboolean
 181 ticket_activate_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 182     options.injections->ticket_activate = g_list_append(options.injections->ticket_activate, g_strdup(optarg));
 183     return TRUE;
 184 }
 185 
 186 static gboolean
 187 ticket_grant_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 188     options.injections->ticket_grant = g_list_append(options.injections->ticket_grant, g_strdup(optarg));
 189     return TRUE;
 190 }
 191 
 192 static gboolean
 193 ticket_revoke_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 194     options.injections->ticket_revoke = g_list_append(options.injections->ticket_revoke, g_strdup(optarg));
 195     return TRUE;
 196 }
 197 
 198 static gboolean
 199 ticket_standby_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 200     options.injections->ticket_standby = g_list_append(options.injections->ticket_standby, g_strdup(optarg));
 201     return TRUE;
 202 }
 203 
 204 static gboolean
 205 utilization_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 206     options.flags |= pcmk_sim_process | pcmk_sim_show_utilization;
 207     return TRUE;
 208 }
 209 
 210 static gboolean
 211 watchdog_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 212     pcmk__str_update(&options.injections->watchdog, optarg);
 213     return TRUE;
 214 }
 215 
 216 static gboolean
 217 xml_file_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 218     pcmk__str_update(&options.xml_file, optarg);
 219     options.flags |= pcmk_sim_sanitized;
 220     return TRUE;
 221 }
 222 
 223 static gboolean
 224 xml_pipe_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     /* [previous][next][first][last][top][bottom][index][help] */
 225     pcmk__str_update(&options.xml_file, "-");
 226     options.flags |= pcmk_sim_sanitized;
 227     return TRUE;
 228 }
 229 
 230 static GOptionEntry operation_entries[] = {
 231     { "run", 'R', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, process_cb,
 232       "Process the supplied input and show what actions the cluster will take in response",
 233       NULL },
 234     { "simulate", 'S', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, simulate_cb,
 235       "Like --run, but also simulate taking those actions and show the resulting new status",
 236       NULL },
 237     { "in-place", 'X', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, in_place_cb,
 238       "Like --simulate, but also store the results back to the input file",
 239       NULL },
 240     { "show-attrs", 'A', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, attrs_cb,
 241       "Show node attributes",
 242       NULL },
 243     { "show-failcounts", 'c', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, failcounts_cb,
 244       "Show resource fail counts",
 245       NULL },
 246     { "show-scores", 's', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, show_scores_cb,
 247       "Show allocation scores",
 248       NULL },
 249     { "show-utilization", 'U', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, utilization_cb,
 250       "Show utilization information",
 251       NULL },
 252     { "profile", 'P', 0, G_OPTION_ARG_FILENAME, &options.test_dir,
 253       "Process all the XML files in the named directory to create profiling data",
 254       "DIR" },
 255     { "repeat", 'N', 0, G_OPTION_ARG_INT, &options.repeat,
 256       "With --profile, repeat each test N times and print timings",
 257       "N" },
 258     /* Deprecated */
 259     { "pending", 'j', G_OPTION_FLAG_NO_ARG|G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, pending_cb,
 260       "Display pending state if 'record-pending' is enabled",
 261       NULL },
 262 
 263     { NULL }
 264 };
 265 
 266 static GOptionEntry synthetic_entries[] = {
 267     { "node-up", 'u', 0, G_OPTION_ARG_CALLBACK, node_up_cb,
 268       "Simulate bringing a node online",
 269       "NODE" },
 270     { "node-down", 'd', 0, G_OPTION_ARG_CALLBACK, node_down_cb,
 271       "Simulate taking a node offline",
 272       "NODE" },
 273     { "node-fail", 'f', 0, G_OPTION_ARG_CALLBACK, node_fail_cb,
 274       "Simulate a node failing",
 275       "NODE" },
 276     { "op-inject", 'i', 0, G_OPTION_ARG_CALLBACK, op_inject_cb,
 277       "Generate a failure for the cluster to react to in the simulation.\n"
 278       INDENT "See `Operation Specification` help for more information.",
 279       "OPSPEC" },
 280     { "op-fail", 'F', 0, G_OPTION_ARG_CALLBACK, op_fail_cb,
 281       "If the specified task occurs during the simulation, have it fail with return code ${rc}.\n"
 282       INDENT "The transition will normally stop at the failed action.\n"
 283       INDENT "Save the result with --save-output and re-run with --xml-file.\n"
 284       INDENT "See `Operation Specification` help for more information.",
 285       "OPSPEC" },
 286     { "set-datetime", 't', 0, G_OPTION_ARG_STRING, &options.use_date,
 287       "Set date/time (ISO 8601 format, see https://en.wikipedia.org/wiki/ISO_8601)",
 288       "DATETIME" },
 289     { "quorum", 'q', 0, G_OPTION_ARG_CALLBACK, quorum_cb,
 290       "Set to '1' (or 'true') to indicate cluster has quorum",
 291       "QUORUM" },
 292     { "watchdog", 'w', 0, G_OPTION_ARG_CALLBACK, watchdog_cb,
 293       "Set to '1' (or 'true') to indicate cluster has an active watchdog device",
 294       "DEVICE" },
 295     { "ticket-grant", 'g', 0, G_OPTION_ARG_CALLBACK, ticket_grant_cb,
 296       "Simulate granting a ticket",
 297       "TICKET" },
 298     { "ticket-revoke", 'r', 0, G_OPTION_ARG_CALLBACK, ticket_revoke_cb,
 299       "Simulate revoking a ticket",
 300       "TICKET" },
 301     { "ticket-standby", 'b', 0, G_OPTION_ARG_CALLBACK, ticket_standby_cb,
 302       "Simulate making a ticket standby",
 303       "TICKET" },
 304     { "ticket-activate", 'e', 0, G_OPTION_ARG_CALLBACK, ticket_activate_cb,
 305       "Simulate activating a ticket",
 306       "TICKET" },
 307 
 308     { NULL }
 309 };
 310 
 311 static GOptionEntry artifact_entries[] = {
 312     { "save-input", 'I', 0, G_OPTION_ARG_FILENAME, &options.input_file,
 313       "Save the input configuration to the named file",
 314       "FILE" },
 315     { "save-output", 'O', 0, G_OPTION_ARG_FILENAME, &options.output_file,
 316       "Save the output configuration to the named file",
 317       "FILE" },
 318     { "save-graph", 'G', 0, G_OPTION_ARG_CALLBACK, save_graph_cb,
 319       "Save the transition graph (XML format) to the named file",
 320       "FILE" },
 321     { "save-dotfile", 'D', 0, G_OPTION_ARG_CALLBACK, save_dotfile_cb,
 322       "Save the transition graph (DOT format) to the named file",
 323       "FILE" },
 324     { "all-actions", 'a', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, all_actions_cb,
 325       "Display all possible actions in DOT graph (even if not part of transition)",
 326       NULL },
 327 
 328     { NULL }
 329 };
 330 
 331 static GOptionEntry source_entries[] = {
 332     { "live-check", 'L', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, live_check_cb,
 333       "Connect to CIB manager and use the current CIB contents as input",
 334       NULL },
 335     { "xml-file", 'x', 0, G_OPTION_ARG_CALLBACK, xml_file_cb,
 336       "Retrieve XML from the named file",
 337       "FILE" },
 338     { "xml-pipe", 'p', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, xml_pipe_cb,
 339       "Retrieve XML from stdin",
 340       NULL },
 341 
 342     { NULL }
 343 };
 344 
 345 static int
 346 setup_input(pcmk__output_t *out, const char *input, const char *output,
     /* [previous][next][first][last][top][bottom][index][help] */
 347             GError **error)
 348 {
 349     int rc = pcmk_rc_ok;
 350     xmlNode *cib_object = NULL;
 351     char *local_output = NULL;
 352 
 353     if (input == NULL) {
 354         /* Use live CIB */
 355         rc = cib__signon_query(out, NULL, &cib_object);
 356         if (rc != pcmk_rc_ok) {
 357             // cib__signon_query() outputs any relevant error
 358             return rc;
 359         }
 360 
 361     } else if (pcmk__str_eq(input, "-", pcmk__str_casei)) {
 362         cib_object = filename2xml(NULL);
 363 
 364     } else {
 365         cib_object = filename2xml(input);
 366     }
 367 
 368     if (pcmk_find_cib_element(cib_object, XML_CIB_TAG_STATUS) == NULL) {
 369         create_xml_node(cib_object, XML_CIB_TAG_STATUS);
 370     }
 371 
 372     if (cli_config_update(&cib_object, NULL, FALSE) == FALSE) {
 373         free_xml(cib_object);
 374         return pcmk_rc_transform_failed;
 375     }
 376 
 377     if (validate_xml(cib_object, NULL, FALSE) != TRUE) {
 378         free_xml(cib_object);
 379         return pcmk_rc_schema_validation;
 380     }
 381 
 382     if (output == NULL) {
 383         char *pid = pcmk__getpid_s();
 384 
 385         local_output = get_shadow_file(pid);
 386         temp_shadow = strdup(local_output);
 387         output = local_output;
 388         free(pid);
 389     }
 390 
 391     rc = write_xml_file(cib_object, output, FALSE);
 392     free_xml(cib_object);
 393     cib_object = NULL;
 394 
 395     if (rc < 0) {
 396         rc = pcmk_legacy2rc(rc);
 397         g_set_error(error, PCMK__EXITC_ERROR, CRM_EX_CANTCREAT,
 398                     "Could not create '%s': %s", output, pcmk_rc_str(rc));
 399         return rc;
 400     } else {
 401         setenv("CIB_file", output, 1);
 402         free(local_output);
 403         return pcmk_rc_ok;
 404     }
 405 }
 406 
 407 static GOptionContext *
 408 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) {
     /* [previous][next][first][last][top][bottom][index][help] */
 409     GOptionContext *context = NULL;
 410 
 411     GOptionEntry extra_prog_entries[] = {
 412         { "quiet", 'Q', 0, G_OPTION_ARG_NONE, &(args->quiet),
 413           "Display only essential output",
 414           NULL },
 415 
 416         { NULL }
 417     };
 418 
 419     const char *description = "Operation Specification:\n\n"
 420                               "The OPSPEC in any command line option is of the form\n"
 421                               "${resource}_${task}_${interval_in_ms}@${node}=${rc}\n"
 422                               "(memcached_monitor_20000@bart.example.com=7, for example).\n"
 423                               "${rc} is an OCF return code.  For more information on these\n"
 424                               "return codes, refer to https://clusterlabs.org/pacemaker/doc/2.1/Pacemaker_Administration/html/agents.html#ocf-return-codes\n\n"
 425                               "Examples:\n\n"
 426                               "Pretend a recurring monitor action found memcached stopped on node\n"
 427                               "fred.example.com and, during recovery, that the memcached stop\n"
 428                               "action failed:\n\n"
 429                               "\tcrm_simulate -LS --op-inject memcached:0_monitor_20000@bart.example.com=7 "
 430                               "--op-fail memcached:0_stop_0@fred.example.com=1 --save-output /tmp/memcached-test.xml\n\n"
 431                               "Now see what the reaction to the stop failed would be:\n\n"
 432                               "\tcrm_simulate -S --xml-file /tmp/memcached-test.xml\n\n";
 433 
 434     context = pcmk__build_arg_context(args, "text (default), xml", group, NULL);
 435     pcmk__add_main_args(context, extra_prog_entries);
 436     g_option_context_set_description(context, description);
 437 
 438     pcmk__add_arg_group(context, "operations", "Operations:",
 439                         "Show operations options", operation_entries);
 440     pcmk__add_arg_group(context, "synthetic", "Synthetic Cluster Events:",
 441                         "Show synthetic cluster event options", synthetic_entries);
 442     pcmk__add_arg_group(context, "artifact", "Artifact Options:",
 443                         "Show artifact options", artifact_entries);
 444     pcmk__add_arg_group(context, "source", "Data Source:",
 445                         "Show data source options", source_entries);
 446 
 447     return context;
 448 }
 449 
 450 int
 451 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 452 {
 453     int rc = pcmk_rc_ok;
 454     pcmk_scheduler_t *scheduler = NULL;
 455     pcmk__output_t *out = NULL;
 456 
 457     GError *error = NULL;
 458 
 459     GOptionGroup *output_group = NULL;
 460     pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
 461     gchar **processed_args = pcmk__cmdline_preproc(argv, "bdefgiqrtuwxDFGINOP");
 462     GOptionContext *context = build_arg_context(args, &output_group);
 463 
 464     options.injections = calloc(1, sizeof(pcmk_injections_t));
 465     if (options.injections == NULL) {
 466         rc = ENOMEM;
 467         goto done;
 468     }
 469 
 470     /* This must come before g_option_context_parse_strv. */
 471     options.xml_file = strdup("-");
 472 
 473     pcmk__register_formats(output_group, formats);
 474     if (!g_option_context_parse_strv(context, &processed_args, &error)) {
 475         exit_code = CRM_EX_USAGE;
 476         goto done;
 477     }
 478 
 479     pcmk__cli_init_logging("crm_simulate", args->verbosity);
 480 
 481     rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv);
 482     if (rc != pcmk_rc_ok) {
 483         fprintf(stderr, "Error creating output format %s: %s\n",
 484                 args->output_ty, pcmk_rc_str(rc));
 485         exit_code = CRM_EX_ERROR;
 486         goto done;
 487     }
 488 
 489     if (pcmk__str_eq(args->output_ty, "text", pcmk__str_null_matches) &&
 490         !pcmk_is_set(options.flags, pcmk_sim_show_scores) &&
 491         !pcmk_is_set(options.flags, pcmk_sim_show_utilization)) {
 492         pcmk__force_args(context, &error, "%s --text-fancy", g_get_prgname());
 493     } else if (pcmk__str_eq(args->output_ty, "xml", pcmk__str_none)) {
 494         pcmk__force_args(context, &error, "%s --xml-simple-list --xml-substitute", g_get_prgname());
 495     }
 496 
 497     pe__register_messages(out);
 498     pcmk__register_lib_messages(out);
 499 
 500     out->quiet = args->quiet;
 501 
 502     if (args->version) {
 503         out->version(out, false);
 504         goto done;
 505     }
 506 
 507     if (args->verbosity > 0) {
 508         options.flags |= pcmk_sim_verbose;
 509 
 510 #ifdef PCMK__COMPAT_2_0
 511         /* Redirect stderr to stdout so we can grep the output */
 512         close(STDERR_FILENO);
 513         dup2(STDOUT_FILENO, STDERR_FILENO);
 514 #endif
 515     }
 516 
 517     scheduler = pe_new_working_set();
 518     if (scheduler == NULL) {
 519         rc = ENOMEM;
 520         g_set_error(&error, PCMK__RC_ERROR, rc,
 521                     "Could not allocate scheduler data");
 522         goto done;
 523     }
 524 
 525     if (pcmk_is_set(options.flags, pcmk_sim_show_scores)) {
 526         pe__set_working_set_flags(scheduler, pcmk_sched_output_scores);
 527     }
 528     if (pcmk_is_set(options.flags, pcmk_sim_show_utilization)) {
 529         pe__set_working_set_flags(scheduler, pcmk_sched_show_utilization);
 530     }
 531     pe__set_working_set_flags(scheduler, pcmk_sched_no_compat);
 532 
 533     if (options.test_dir != NULL) {
 534         scheduler->priv = out;
 535         pcmk__profile_dir(options.test_dir, options.repeat, scheduler,
 536                           options.use_date);
 537         rc = pcmk_rc_ok;
 538         goto done;
 539     }
 540 
 541     rc = setup_input(out, options.xml_file,
 542                      options.store? options.xml_file : options.output_file,
 543                      &error);
 544     if (rc != pcmk_rc_ok) {
 545         goto done;
 546     }
 547 
 548     rc = pcmk__simulate(scheduler, out, options.injections, options.flags,
 549                         section_opts, options.use_date, options.input_file,
 550                         options.graph_file, options.dot_file);
 551 
 552   done:
 553     pcmk__output_and_clear_error(&error, NULL);
 554 
 555     /* There sure is a lot to free in options. */
 556     free(options.dot_file);
 557     free(options.graph_file);
 558     g_free(options.input_file);
 559     g_free(options.output_file);
 560     g_free(options.test_dir);
 561     free(options.use_date);
 562     free(options.xml_file);
 563 
 564     pcmk_free_injections(options.injections);
 565     pcmk__free_arg_context(context);
 566     g_strfreev(processed_args);
 567 
 568     if (scheduler != NULL) {
 569         pe_free_working_set(scheduler);
 570     }
 571 
 572     fflush(stderr);
 573 
 574     if (temp_shadow) {
 575         unlink(temp_shadow);
 576         free(temp_shadow);
 577     }
 578 
 579     if (rc != pcmk_rc_ok) {
 580         exit_code = pcmk_rc2exitc(rc);
 581     }
 582 
 583     if (out != NULL) {
 584         out->finish(out, exit_code, true, NULL);
 585         pcmk__output_free(out);
 586     }
 587 
 588     pcmk__unregister_formats();
 589     crm_exit(exit_code);
 590 }

/* [previous][next][first][last][top][bottom][index][help] */