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

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