root/tools/crm_simulate.c

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

DEFINITIONS

This source file includes following definitions.
  1. get_date
  2. print_cluster_status
  3. create_action_name
  4. create_dotfile
  5. setup_input
  6. profile_one
  7. profile_all
  8. count_resources
  9. main

   1 /*
   2  * Copyright (C) 2009 Andrew Beekhof <andrew@beekhof.net>
   3  *
   4  * This program is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2 of the License, or (at your option) any later version.
   8  *
   9  * This software is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12  * General Public License for more details.
  13  *
  14  * You should have received a copy of the GNU General Public
  15  * License along with this library; if not, write to the Free Software
  16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17  */
  18 
  19 #include <crm_internal.h>
  20 
  21 #include <stdio.h>
  22 #include <unistd.h>
  23 #include <stdlib.h>
  24 
  25 #include <sys/stat.h>
  26 #include <sys/param.h>
  27 #include <sys/types.h>
  28 #include <dirent.h>
  29 
  30 #include <crm/crm.h>
  31 #include <crm/cib.h>
  32 #include <crm/common/util.h>
  33 #include <crm/transition.h>
  34 #include <crm/common/iso8601.h>
  35 #include <crm/pengine/status.h>
  36 #include <allocate.h>
  37 #include "fake_transition.h"
  38 
  39 cib_t *global_cib = NULL;
  40 GListPtr op_fail = NULL;
  41 bool action_numbers = FALSE;
  42 gboolean quiet = FALSE;
  43 gboolean print_pending = TRUE;
  44 char *temp_shadow = NULL;
  45 extern gboolean bringing_nodes_online;
  46 
  47 #define quiet_log(fmt, args...) do {            \
  48         if(quiet == FALSE) {                    \
  49             printf(fmt , ##args);               \
  50         }                                       \
  51     } while(0)
  52 
  53 extern void cleanup_alloc_calculations(pe_working_set_t * data_set);
  54 
  55 extern xmlNode *do_calculations(pe_working_set_t * data_set, xmlNode * xml_input, crm_time_t * now);
  56 
  57 char *use_date = NULL;
  58 
  59 static void
  60 get_date(pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
  61 {
  62     int value = 0;
  63     time_t original_date = 0;
  64 
  65     crm_element_value_int(data_set->input, "execution-date", &value);
  66     original_date = value;
  67 
  68     if (use_date) {
  69         data_set->now = crm_time_new(use_date);
  70 
  71     } else if(original_date) {
  72         char *when = NULL;
  73 
  74         data_set->now = crm_time_new(NULL);
  75         crm_time_set_timet(data_set->now, &original_date);
  76 
  77         when = crm_time_as_string(data_set->now, crm_time_log_date|crm_time_log_timeofday);
  78         printf("Using the original execution date of: %s\n", when);
  79 
  80         free(when);
  81     }
  82 }
  83 
  84 static void
  85 print_cluster_status(pe_working_set_t * data_set, long options)
     /* [previous][next][first][last][top][bottom][index][help] */
  86 {
  87     char *online_nodes = NULL;
  88     char *online_remote_nodes = NULL;
  89     char *online_remote_containers = NULL;
  90     char *offline_nodes = NULL;
  91     char *offline_remote_nodes = NULL;
  92 
  93     GListPtr gIter = NULL;
  94 
  95     for (gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
  96         node_t *node = (node_t *) gIter->data;
  97         const char *node_mode = NULL;
  98         char *node_name = NULL;
  99 
 100         if (is_container_remote_node(node)) {
 101             node_name = crm_strdup_printf("%s:%s", node->details->uname, node->details->remote_rsc->container->id);
 102         } else {
 103             node_name = crm_strdup_printf("%s", node->details->uname);
 104         }
 105 
 106         if (node->details->unclean) {
 107             if (node->details->online && node->details->unclean) {
 108                 node_mode = "UNCLEAN (online)";
 109 
 110             } else if (node->details->pending) {
 111                 node_mode = "UNCLEAN (pending)";
 112 
 113             } else {
 114                 node_mode = "UNCLEAN (offline)";
 115             }
 116 
 117         } else if (node->details->pending) {
 118             node_mode = "pending";
 119 
 120         } else if (node->details->standby_onfail && node->details->online) {
 121             node_mode = "standby (on-fail)";
 122 
 123         } else if (node->details->standby) {
 124             if (node->details->online) {
 125                 node_mode = "standby";
 126             } else {
 127                 node_mode = "OFFLINE (standby)";
 128             }
 129 
 130         } else if (node->details->maintenance) {
 131             if (node->details->online) {
 132                 node_mode = "maintenance";
 133             } else {
 134                 node_mode = "OFFLINE (maintenance)";
 135             }
 136 
 137         } else if (node->details->online) {
 138             if (is_container_remote_node(node)) {
 139                 online_remote_containers = add_list_element(online_remote_containers, node_name);
 140             } else if (is_baremetal_remote_node(node)) {
 141                 online_remote_nodes = add_list_element(online_remote_nodes, node_name);
 142             } else {
 143                 online_nodes = add_list_element(online_nodes, node_name);
 144             }
 145             free(node_name);
 146             continue;
 147 
 148         } else {
 149             if (is_baremetal_remote_node(node)) {
 150                 offline_remote_nodes = add_list_element(offline_remote_nodes, node_name);
 151             } else if (is_container_remote_node(node)) {
 152                 /* ignore offline container nodes */
 153             } else {
 154                 offline_nodes = add_list_element(offline_nodes, node_name);
 155             }
 156             free(node_name);
 157             continue;
 158         }
 159 
 160         if (is_container_remote_node(node)) {
 161             printf("ContainerNode %s: %s\n", node_name, node_mode);
 162         } else if (is_baremetal_remote_node(node)) {
 163             printf("RemoteNode %s: %s\n", node_name, node_mode);
 164         } else if (safe_str_eq(node->details->uname, node->details->id)) {
 165             printf("Node %s: %s\n", node_name, node_mode);
 166         } else {
 167             printf("Node %s (%s): %s\n", node_name, node->details->id, node_mode);
 168         }
 169 
 170         free(node_name);
 171     }
 172 
 173     if (online_nodes) {
 174         printf("Online: [%s ]\n", online_nodes);
 175         free(online_nodes);
 176     }
 177     if (offline_nodes) {
 178         printf("OFFLINE: [%s ]\n", offline_nodes);
 179         free(offline_nodes);
 180     }
 181     if (online_remote_nodes) {
 182         printf("RemoteOnline: [%s ]\n", online_remote_nodes);
 183         free(online_remote_nodes);
 184     }
 185     if (offline_remote_nodes) {
 186         printf("RemoteOFFLINE: [%s ]\n", offline_remote_nodes);
 187         free(offline_remote_nodes);
 188     }
 189     if (online_remote_containers) {
 190         printf("Containers: [%s ]\n", online_remote_containers);
 191         free(online_remote_containers);
 192     }
 193 
 194     fprintf(stdout, "\n");
 195     for (gIter = data_set->resources; gIter != NULL; gIter = gIter->next) {
 196         resource_t *rsc = (resource_t *) gIter->data;
 197 
 198         if (is_set(rsc->flags, pe_rsc_orphan)
 199             && rsc->role == RSC_ROLE_STOPPED) {
 200             continue;
 201         }
 202         rsc->fns->print(rsc, NULL, pe_print_printf | options, stdout);
 203     }
 204     fprintf(stdout, "\n");
 205 }
 206 
 207 static char *
 208 create_action_name(action_t * action)
     /* [previous][next][first][last][top][bottom][index][help] */
 209 {
 210     char *action_name = NULL;
 211     const char *prefix = NULL;
 212     const char *action_host = NULL;
 213     const char *task = action->task;
 214 
 215     if (action->node) {
 216         action_host = action->node->details->uname;
 217     } else if (is_not_set(action->flags, pe_action_pseudo)) {
 218         action_host = "<none>";
 219     }
 220 
 221     if (safe_str_eq(action->task, RSC_CANCEL)) {
 222         prefix = "Cancel ";
 223         task = "monitor";       /* TO-DO: Hack! */
 224     }
 225 
 226     if (action->rsc && action->rsc->clone_name) {
 227         char *key = NULL;
 228         const char *name = action->rsc->clone_name;
 229         const char *interval_s = g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL);
 230 
 231         int interval = crm_parse_int(interval_s, "0");
 232 
 233         if (safe_str_eq(action->task, RSC_NOTIFY)
 234             || safe_str_eq(action->task, RSC_NOTIFIED)) {
 235             const char *n_type = g_hash_table_lookup(action->meta, "notify_key_type");
 236             const char *n_task = g_hash_table_lookup(action->meta, "notify_key_operation");
 237 
 238             CRM_ASSERT(n_type != NULL);
 239             CRM_ASSERT(n_task != NULL);
 240             key = generate_notify_key(name, n_type, n_task);
 241 
 242         } else {
 243             key = generate_op_key(name, task, interval);
 244         }
 245 
 246         if (action_host) {
 247             action_name = crm_strdup_printf("%s%s %s", prefix ? prefix : "", key, action_host);
 248         } else {
 249             action_name = crm_strdup_printf("%s%s", prefix ? prefix : "", key);
 250         }
 251         free(key);
 252 
 253     } else if (safe_str_eq(action->task, CRM_OP_FENCE)) {
 254         const char *op = g_hash_table_lookup(action->meta, "stonith_action");
 255 
 256         action_name = crm_strdup_printf("%s%s '%s' %s", prefix ? prefix : "", action->task, op, action_host);
 257 
 258     } else if (action->rsc && action_host) {
 259         action_name = crm_strdup_printf("%s%s %s", prefix ? prefix : "", action->uuid, action_host);
 260 
 261     } else if (action_host) {
 262         action_name = crm_strdup_printf("%s%s %s", prefix ? prefix : "", action->task, action_host);
 263 
 264     } else {
 265         action_name = crm_strdup_printf("%s", action->uuid);
 266     }
 267 
 268     if(action_numbers) {
 269         char *with_id = crm_strdup_printf("%s (%d)", action_name, action->id);
 270 
 271         free(action_name);
 272         action_name = with_id;
 273     }
 274     return action_name;
 275 }
 276 
 277 static void
 278 create_dotfile(pe_working_set_t * data_set, const char *dot_file, gboolean all_actions)
     /* [previous][next][first][last][top][bottom][index][help] */
 279 {
 280     GListPtr gIter = NULL;
 281     FILE *dot_strm = fopen(dot_file, "w");
 282 
 283     if (dot_strm == NULL) {
 284         crm_perror(LOG_ERR, "Could not open %s for writing", dot_file);
 285         return;
 286     }
 287 
 288     fprintf(dot_strm, " digraph \"g\" {\n");
 289     for (gIter = data_set->actions; gIter != NULL; gIter = gIter->next) {
 290         action_t *action = (action_t *) gIter->data;
 291         const char *style = "dashed";
 292         const char *font = "black";
 293         const char *color = "black";
 294         char *action_name = create_action_name(action);
 295 
 296         crm_trace("Action %d: %s %s %p", action->id, action_name, action->uuid, action);
 297 
 298         if (is_set(action->flags, pe_action_pseudo)) {
 299             font = "orange";
 300         }
 301 
 302         if (is_set(action->flags, pe_action_dumped)) {
 303             style = "bold";
 304             color = "green";
 305 
 306         } else if (action->rsc != NULL && is_not_set(action->rsc->flags, pe_rsc_managed)) {
 307             color = "red";
 308             font = "purple";
 309             if (all_actions == FALSE) {
 310                 goto dont_write;
 311             }
 312 
 313         } else if (is_set(action->flags, pe_action_optional)) {
 314             color = "blue";
 315             if (all_actions == FALSE) {
 316                 goto dont_write;
 317             }
 318 
 319         } else {
 320             color = "red";
 321             CRM_CHECK(is_set(action->flags, pe_action_runnable) == FALSE,;
 322                 );
 323         }
 324 
 325         set_bit(action->flags, pe_action_dumped);
 326         crm_trace("\"%s\" [ style=%s color=\"%s\" fontcolor=\"%s\"]",
 327                 action_name, style, color, font);
 328         fprintf(dot_strm, "\"%s\" [ style=%s color=\"%s\" fontcolor=\"%s\"]\n",
 329                 action_name, style, color, font);
 330   dont_write:
 331         free(action_name);
 332     }
 333 
 334     for (gIter = data_set->actions; gIter != NULL; gIter = gIter->next) {
 335         action_t *action = (action_t *) gIter->data;
 336 
 337         GListPtr gIter2 = NULL;
 338 
 339         for (gIter2 = action->actions_before; gIter2 != NULL; gIter2 = gIter2->next) {
 340             action_wrapper_t *before = (action_wrapper_t *) gIter2->data;
 341 
 342             char *before_name = NULL;
 343             char *after_name = NULL;
 344             const char *style = "dashed";
 345             gboolean optional = TRUE;
 346 
 347             if (before->state == pe_link_dumped) {
 348                 optional = FALSE;
 349                 style = "bold";
 350             } else if (is_set(action->flags, pe_action_pseudo)
 351                        && (before->type & pe_order_stonith_stop)) {
 352                 continue;
 353             } else if (before->state == pe_link_dup) {
 354                 continue;
 355             } else if (before->type == pe_order_none) {
 356                 continue;
 357             } else if (is_set(before->action->flags, pe_action_dumped)
 358                        && is_set(action->flags, pe_action_dumped)
 359                        && before->type != pe_order_load) {
 360                 optional = FALSE;
 361             }
 362 
 363             if (all_actions || optional == FALSE) {
 364                 before_name = create_action_name(before->action);
 365                 after_name = create_action_name(action);
 366                 crm_trace("\"%s\" -> \"%s\" [ style = %s]",
 367                         before_name, after_name, style);
 368                 fprintf(dot_strm, "\"%s\" -> \"%s\" [ style = %s]\n",
 369                         before_name, after_name, style);
 370                 free(before_name);
 371                 free(after_name);
 372             }
 373         }
 374     }
 375 
 376     fprintf(dot_strm, "}\n");
 377     if (dot_strm != NULL) {
 378         fflush(dot_strm);
 379         fclose(dot_strm);
 380     }
 381 }
 382 
 383 static void
 384 setup_input(const char *input, const char *output)
     /* [previous][next][first][last][top][bottom][index][help] */
 385 {
 386     int rc = pcmk_ok;
 387     cib_t *cib_conn = NULL;
 388     xmlNode *cib_object = NULL;
 389     char *local_output = NULL;
 390 
 391     if (input == NULL) {
 392         /* Use live CIB */
 393         cib_conn = cib_new();
 394         rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command);
 395 
 396         if (rc == pcmk_ok) {
 397             rc = cib_conn->cmds->query(cib_conn, NULL, &cib_object, cib_scope_local | cib_sync_call);
 398         }
 399 
 400         cib_conn->cmds->signoff(cib_conn);
 401         cib_delete(cib_conn);
 402         cib_conn = NULL;
 403 
 404         if (rc != pcmk_ok) {
 405             fprintf(stderr, "Live CIB query failed: %s (%d)\n", pcmk_strerror(rc), rc);
 406             crm_exit(rc);
 407 
 408         } else if (cib_object == NULL) {
 409             fprintf(stderr, "Live CIB query failed: empty result\n");
 410             crm_exit(ENOTCONN);
 411         }
 412 
 413     } else if (safe_str_eq(input, "-")) {
 414         cib_object = filename2xml(NULL);
 415 
 416     } else {
 417         cib_object = filename2xml(input);
 418     }
 419 
 420     if (get_object_root(XML_CIB_TAG_STATUS, cib_object) == NULL) {
 421         create_xml_node(cib_object, XML_CIB_TAG_STATUS);
 422     }
 423 
 424     if (cli_config_update(&cib_object, NULL, FALSE) == FALSE) {
 425         free_xml(cib_object);
 426         crm_exit(ENOKEY);
 427     }
 428 
 429     if (validate_xml(cib_object, NULL, FALSE) != TRUE) {
 430         free_xml(cib_object);
 431         crm_exit(pcmk_err_schema_validation);
 432     }
 433 
 434     if (output == NULL) {
 435         char *pid = crm_getpid_s();
 436 
 437         local_output = get_shadow_file(pid);
 438         temp_shadow = strdup(local_output);
 439         output = local_output;
 440         free(pid);
 441     }
 442 
 443     rc = write_xml_file(cib_object, output, FALSE);
 444     free_xml(cib_object);
 445     cib_object = NULL;
 446 
 447     if (rc < 0) {
 448         fprintf(stderr, "Could not create '%s': %s\n", output, strerror(errno));
 449         crm_exit(rc);
 450     }
 451     setenv("CIB_file", output, 1);
 452     free(local_output);
 453 }
 454 
 455 
 456 /* *INDENT-OFF* */
 457 static struct crm_option long_options[] = {
 458     /* Top-level Options */
 459     {"help",    0, 0, '?', "\tThis text"},
 460     {"version", 0, 0, '$', "\tVersion information"  },
 461     {"quiet",   0, 0, 'Q', "\tDisplay only essentialoutput"},
 462     {"verbose", 0, 0, 'V', "\tIncrease debug output"},
 463 
 464     {"-spacer-",      0, 0, '-', "\nOperations:"},
 465     {"run",           0, 0, 'R', "\tDetermine the cluster's response to the given configuration and status"},
 466     {"simulate",      0, 0, 'S', "Simulate the transition's execution and display the resulting cluster status"},
 467     {"in-place",      0, 0, 'X', "Simulate the transition's execution and store the result back to the input file"},
 468     {"show-scores",   0, 0, 's', "Show allocation scores"},
 469     {"show-utilization",   0, 0, 'U', "Show utilization information"},
 470     {"profile",       1, 0, 'P', "Run all tests in the named directory to create profiling data"},
 471     {"pending",       0, 0, 'j', "\tDisplay pending state if 'record-pending' is enabled", pcmk_option_hidden},
 472 
 473     {"-spacer-",     0, 0, '-', "\nSynthetic Cluster Events:"},
 474     {"node-up",      1, 0, 'u', "\tBring a node online"},
 475     {"node-down",    1, 0, 'd', "\tTake a node offline"},
 476     {"node-fail",    1, 0, 'f', "\tMark a node as failed"},
 477     {"op-inject",    1, 0, 'i', "\tGenerate a failure for the cluster to react to in the simulation"},
 478     {"-spacer-",     0, 0, '-', "\t\tValue is of the form ${resource}_${task}_${interval}@${node}=${rc}."},
 479     {"-spacer-",     0, 0, '-', "\t\tEg. memcached_monitor_20000@bart.example.com=7"},
 480     {"-spacer-",     0, 0, '-', "\t\tFor more information on OCF return codes, refer to: http://www.clusterlabs.org/doc/en-US/Pacemaker/1.1/html/Pacemaker_Explained/s-ocf-return-codes.html"},
 481     {"op-fail",      1, 0, 'F', "\tIf the specified task occurs during the simulation, have it fail with return code ${rc}"},
 482     {"-spacer-",     0, 0, '-', "\t\tValue is of the form ${resource}_${task}_${interval}@${node}=${rc}."},
 483     {"-spacer-",     0, 0, '-', "\t\tEg. memcached_stop_0@bart.example.com=1\n"},
 484     {"-spacer-",     0, 0, '-', "\t\tThe transition will normally stop at the failed action.  Save the result with --save-output and re-run with --xml-file"},
 485     {"set-datetime", 1, 0, 't', "Set date/time"},
 486     {"quorum",       1, 0, 'q', "\tSpecify a value for quorum"},
 487     {"watchdog",     1, 0, 'w', "\tAssume a watchdog device is active"},
 488     {"ticket-grant",     1, 0, 'g', "Grant a ticket"},
 489     {"ticket-revoke",    1, 0, 'r', "Revoke a ticket"},
 490     {"ticket-standby",   1, 0, 'b', "Make a ticket standby"},
 491     {"ticket-activate",  1, 0, 'e', "Activate a ticket"},
 492 
 493     {"-spacer-",     0, 0, '-', "\nOutput Options:"},
 494 
 495     {"save-input",   1, 0, 'I', "\tSave the input configuration to the named file"},
 496     {"save-output",  1, 0, 'O', "Save the output configuration to the named file"},
 497     {"save-graph",   1, 0, 'G', "\tSave the transition graph (XML format) to the named file"},
 498     {"save-dotfile", 1, 0, 'D', "Save the transition graph (DOT format) to the named file"},
 499     {"all-actions",  0, 0, 'a', "\tDisplay all possible actions in the DOT graph - even ones not part of the transition"},
 500 
 501     {"-spacer-",    0, 0, '-', "\nData Source:"},
 502     {"live-check",  0, 0, 'L', "\tConnect to the CIB and use the current contents as input"},
 503     {"xml-file",    1, 0, 'x', "\tRetrieve XML from the named file"},
 504     {"xml-pipe",    0, 0, 'p', "\tRetrieve XML from stdin"},
 505 
 506     {"-spacer-",    0, 0, '-', "\nExamples:\n"},
 507     {"-spacer-",    0, 0, '-', "Pretend a recurring monitor action found memcached stopped on node fred.example.com and, during recovery, that the memcached stop action failed", pcmk_option_paragraph},
 508     {"-spacer-",    0, 0, '-', " crm_simulate -LS --op-inject memcached:0_monitor_20000@bart.example.com=7 --op-fail memcached:0_stop_0@fred.example.com=1 --save-output /tmp/memcached-test.xml", pcmk_option_example},
 509     {"-spacer-",    0, 0, '-', "Now see what the reaction to the stop failure would be", pcmk_option_paragraph},
 510     {"-spacer-",    0, 0, '-', " crm_simulate -S --xml-file /tmp/memcached-test.xml", pcmk_option_example},
 511 
 512     {0, 0, 0, 0}
 513 };
 514 /* *INDENT-ON* */
 515 
 516 static void
 517 profile_one(const char *xml_file)
     /* [previous][next][first][last][top][bottom][index][help] */
 518 {
 519     xmlNode *cib_object = NULL;
 520     pe_working_set_t data_set;
 521 
 522     printf("* Testing %s\n", xml_file);
 523     cib_object = filename2xml(xml_file);
 524     if (get_object_root(XML_CIB_TAG_STATUS, cib_object) == NULL) {
 525         create_xml_node(cib_object, XML_CIB_TAG_STATUS);
 526     }
 527 
 528     if (cli_config_update(&cib_object, NULL, FALSE) == FALSE) {
 529         free_xml(cib_object);
 530         return;
 531     }
 532 
 533     if (validate_xml(cib_object, NULL, FALSE) != TRUE) {
 534         free_xml(cib_object);
 535         return;
 536     }
 537 
 538     set_working_set_defaults(&data_set);
 539 
 540     data_set.input = cib_object;
 541     get_date(&data_set);
 542     do_calculations(&data_set, cib_object, NULL);
 543 
 544     cleanup_alloc_calculations(&data_set);
 545 }
 546 
 547 #ifndef FILENAME_MAX
 548 #  define FILENAME_MAX 512
 549 #endif
 550 
 551 static int
 552 profile_all(const char *dir)
     /* [previous][next][first][last][top][bottom][index][help] */
 553 {
 554     struct dirent **namelist;
 555 
 556     int lpc = 0;
 557     int file_num = scandir(dir, &namelist, 0, alphasort);
 558 
 559     if (file_num > 0) {
 560         struct stat prop;
 561         char buffer[FILENAME_MAX];
 562 
 563         while (file_num--) {
 564             if ('.' == namelist[file_num]->d_name[0]) {
 565                 free(namelist[file_num]);
 566                 continue;
 567 
 568             } else if (!crm_ends_with_ext(namelist[file_num]->d_name, ".xml")) {
 569                 free(namelist[file_num]);
 570                 continue;
 571             }
 572 
 573             lpc++;
 574             snprintf(buffer, sizeof(buffer), "%s/%s", dir, namelist[file_num]->d_name);
 575             if (stat(buffer, &prop) == 0 && S_ISREG(prop.st_mode)) {
 576                 profile_one(buffer);
 577             }
 578             free(namelist[file_num]);
 579         }
 580         free(namelist);
 581     }
 582 
 583     return lpc;
 584 }
 585 
 586 static int
 587 count_resources(pe_working_set_t * data_set, resource_t * rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 588 {
 589     int count = 0;
 590     GListPtr gIter = NULL;
 591 
 592     if (rsc == NULL) {
 593         gIter = data_set->resources;
 594     } else if (rsc->children) {
 595         gIter = rsc->children;
 596     } else {
 597         return is_not_set(rsc->flags, pe_rsc_orphan);
 598     }
 599 
 600     for (; gIter != NULL; gIter = gIter->next) {
 601         count += count_resources(data_set, gIter->data);
 602     }
 603     return count;
 604 }
 605 
 606 int
 607 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 608 {
 609     int rc = 0;
 610     guint modified = 0;
 611 
 612     gboolean store = FALSE;
 613     gboolean process = FALSE;
 614     gboolean simulate = FALSE;
 615     gboolean all_actions = FALSE;
 616     gboolean have_stdout = FALSE;
 617 
 618     pe_working_set_t data_set;
 619 
 620     const char *xml_file = "-";
 621     const char *quorum = NULL;
 622     const char *watchdog = NULL;
 623     const char *test_dir = NULL;
 624     const char *dot_file = NULL;
 625     const char *graph_file = NULL;
 626     const char *input_file = NULL;
 627     const char *output_file = NULL;
 628 
 629     int flag = 0;
 630     int index = 0;
 631     int argerr = 0;
 632 
 633     GListPtr node_up = NULL;
 634     GListPtr node_down = NULL;
 635     GListPtr node_fail = NULL;
 636     GListPtr op_inject = NULL;
 637     GListPtr ticket_grant = NULL;
 638     GListPtr ticket_revoke = NULL;
 639     GListPtr ticket_standby = NULL;
 640     GListPtr ticket_activate = NULL;
 641 
 642     xmlNode *input = NULL;
 643 
 644     crm_log_cli_init("crm_simulate");
 645     crm_set_options(NULL, "datasource operation [additional options]",
 646                     long_options, "Tool for simulating the cluster's response to events");
 647 
 648     if (argc < 2) {
 649         crm_help('?', EX_USAGE);
 650     }
 651 
 652     while (1) {
 653         flag = crm_get_option(argc, argv, &index);
 654         if (flag == -1)
 655             break;
 656 
 657         switch (flag) {
 658             case 'V':
 659                 if (have_stdout == FALSE) {
 660                     /* Redirect stderr to stdout so we can grep the output */
 661                     have_stdout = TRUE;
 662                     close(STDERR_FILENO);
 663                     dup2(STDOUT_FILENO, STDERR_FILENO);
 664                 }
 665 
 666                 crm_bump_log_level(argc, argv);
 667                 action_numbers = TRUE;
 668                 break;
 669             case '?':
 670             case '$':
 671                 crm_help(flag, EX_OK);
 672                 break;
 673             case 'p':
 674                 xml_file = "-";
 675                 break;
 676             case 'Q':
 677                 quiet = TRUE;
 678                 break;
 679             case 'L':
 680                 xml_file = NULL;
 681                 break;
 682             case 'x':
 683                 xml_file = optarg;
 684                 break;
 685             case 'u':
 686                 modified++;
 687                 bringing_nodes_online = TRUE;
 688                 node_up = g_list_append(node_up, optarg);
 689                 break;
 690             case 'd':
 691                 modified++;
 692                 node_down = g_list_append(node_down, optarg);
 693                 break;
 694             case 'f':
 695                 modified++;
 696                 node_fail = g_list_append(node_fail, optarg);
 697                 break;
 698             case 't':
 699                 use_date = strdup(optarg);
 700                 break;
 701             case 'i':
 702                 modified++;
 703                 op_inject = g_list_append(op_inject, optarg);
 704                 break;
 705             case 'F':
 706                 process = TRUE;
 707                 simulate = TRUE;
 708                 op_fail = g_list_append(op_fail, optarg);
 709                 break;
 710             case 'w':
 711                 modified++;
 712                 watchdog = optarg;
 713                 break;
 714             case 'q':
 715                 modified++;
 716                 quorum = optarg;
 717                 break;
 718             case 'g':
 719                 modified++;
 720                 ticket_grant = g_list_append(ticket_grant, optarg);
 721                 break;
 722             case 'r':
 723                 modified++;
 724                 ticket_revoke = g_list_append(ticket_revoke, optarg);
 725                 break;
 726             case 'b':
 727                 modified++;
 728                 ticket_standby = g_list_append(ticket_standby, optarg);
 729                 break;
 730             case 'e':
 731                 modified++;
 732                 ticket_activate = g_list_append(ticket_activate, optarg);
 733                 break;
 734             case 'a':
 735                 all_actions = TRUE;
 736                 break;
 737             case 's':
 738                 process = TRUE;
 739                 show_scores = TRUE;
 740                 break;
 741             case 'U':
 742                 process = TRUE;
 743                 show_utilization = TRUE;
 744                 break;
 745             case 'j':
 746                 print_pending = TRUE;
 747                 break;
 748             case 'S':
 749                 process = TRUE;
 750                 simulate = TRUE;
 751                 break;
 752             case 'X':
 753                 store = TRUE;
 754                 process = TRUE;
 755                 simulate = TRUE;
 756                 break;
 757             case 'R':
 758                 process = TRUE;
 759                 break;
 760             case 'D':
 761                 process = TRUE;
 762                 dot_file = optarg;
 763                 break;
 764             case 'G':
 765                 process = TRUE;
 766                 graph_file = optarg;
 767                 break;
 768             case 'I':
 769                 input_file = optarg;
 770                 break;
 771             case 'O':
 772                 output_file = optarg;
 773                 break;
 774             case 'P':
 775                 test_dir = optarg;
 776                 break;
 777             default:
 778                 ++argerr;
 779                 break;
 780         }
 781     }
 782 
 783     if (optind > argc) {
 784         ++argerr;
 785     }
 786 
 787     if (argerr) {
 788         crm_help('?', EX_USAGE);
 789     }
 790 
 791     if (test_dir != NULL) {
 792         return profile_all(test_dir);
 793     }
 794 
 795     setup_input(xml_file, store ? xml_file : output_file);
 796 
 797     global_cib = cib_new();
 798     global_cib->cmds->signon(global_cib, crm_system_name, cib_command);
 799 
 800     set_working_set_defaults(&data_set);
 801 
 802     if (data_set.now != NULL) {
 803         quiet_log(" + Setting effective cluster time: %s", use_date);
 804         crm_time_log(LOG_WARNING, "Set fake 'now' to", data_set.now,
 805                      crm_time_log_date | crm_time_log_timeofday);
 806     }
 807 
 808     rc = global_cib->cmds->query(global_cib, NULL, &input, cib_sync_call | cib_scope_local);
 809     CRM_ASSERT(rc == pcmk_ok);
 810 
 811     data_set.input = input;
 812     get_date(&data_set);
 813     if(xml_file) {
 814         set_bit(data_set.flags, pe_flag_sanitized);
 815     }
 816     cluster_status(&data_set);
 817 
 818     if (quiet == FALSE) {
 819         int options = print_pending ? pe_print_pending : 0;
 820 
 821         if(is_set(data_set.flags, pe_flag_maintenance_mode)) {
 822             quiet_log("\n              *** Resource management is DISABLED ***");
 823             quiet_log("\n  The cluster will not attempt to start, stop or recover services");
 824             quiet_log("\n");
 825         }
 826 
 827         if(data_set.disabled_resources || data_set.blocked_resources) {
 828             quiet_log("%d of %d resources DISABLED and %d BLOCKED from being started due to failures\n",
 829                       data_set.disabled_resources, count_resources(&data_set, NULL), data_set.blocked_resources);
 830         }
 831 
 832         quiet_log("\nCurrent cluster status:\n");
 833         print_cluster_status(&data_set, options);
 834     }
 835 
 836     if (modified) {
 837         quiet_log("Performing requested modifications\n");
 838         modify_configuration(&data_set, global_cib, quorum, watchdog, node_up, node_down, node_fail, op_inject,
 839                              ticket_grant, ticket_revoke, ticket_standby, ticket_activate);
 840 
 841         rc = global_cib->cmds->query(global_cib, NULL, &input, cib_sync_call);
 842         if (rc != pcmk_ok) {
 843             fprintf(stderr, "Could not connect to the CIB for input: %s\n", pcmk_strerror(rc));
 844             goto done;
 845         }
 846 
 847         cleanup_calculations(&data_set);
 848         data_set.input = input;
 849         get_date(&data_set);
 850 
 851         if(xml_file) {
 852             set_bit(data_set.flags, pe_flag_sanitized);
 853         }
 854         cluster_status(&data_set);
 855     }
 856 
 857     if (input_file != NULL) {
 858         rc = write_xml_file(input, input_file, FALSE);
 859         if (rc < 0) {
 860             fprintf(stderr, "Could not create '%s': %s\n", input_file, strerror(errno));
 861             goto done;
 862         }
 863     }
 864 
 865     rc = 0;
 866     if (process || simulate) {
 867         crm_time_t *local_date = NULL;
 868 
 869         if (show_scores && show_utilization) {
 870             printf("Allocation scores and utilization information:\n");
 871         } else if (show_scores) {
 872             fprintf(stdout, "Allocation scores:\n");
 873         } else if (show_utilization) {
 874             printf("Utilization information:\n");
 875         }
 876 
 877         do_calculations(&data_set, input, local_date);
 878         input = NULL;           /* Don't try and free it twice */
 879 
 880         if (graph_file != NULL) {
 881             write_xml_file(data_set.graph, graph_file, FALSE);
 882         }
 883 
 884         if (dot_file != NULL) {
 885             create_dotfile(&data_set, dot_file, all_actions);
 886         }
 887 
 888         if (quiet == FALSE) {
 889             GListPtr gIter = NULL;
 890 
 891             quiet_log("%sTransition Summary:\n", show_scores || show_utilization
 892                       || modified ? "\n" : "");
 893             fflush(stdout);
 894 
 895             LogNodeActions(&data_set, TRUE);
 896             for (gIter = data_set.resources; gIter != NULL; gIter = gIter->next) {
 897                 resource_t *rsc = (resource_t *) gIter->data;
 898 
 899                 LogActions(rsc, &data_set, TRUE);
 900             }
 901         }
 902     }
 903 
 904     if (simulate) {
 905         rc = run_simulation(&data_set, global_cib, op_fail, quiet);
 906         if(quiet == FALSE) {
 907             get_date(&data_set);
 908 
 909             quiet_log("\nRevised cluster status:\n");
 910             cluster_status(&data_set);
 911             print_cluster_status(&data_set, 0);
 912         }
 913     }
 914 
 915   done:
 916     cleanup_alloc_calculations(&data_set);
 917 
 918     global_cib->cmds->signoff(global_cib);
 919     cib_delete(global_cib);
 920     free(use_date);
 921     fflush(stderr);
 922 
 923     if (temp_shadow) {
 924         unlink(temp_shadow);
 925         free(temp_shadow);
 926     }
 927     return crm_exit(rc);
 928 }

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