root/pengine/ptest.c

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

DEFINITIONS

This source file includes following definitions.
  1. init_dotfile
  2. create_action_name
  3. main

   1 
   2 /* 
   3  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
   4  * 
   5  * This program is free software; you can redistribute it and/or
   6  * modify it under the terms of the GNU General Public
   7  * License as published by the Free Software Foundation; either
   8  * version 2 of the License, or (at your option) any later version.
   9  * 
  10  * This software is distributed in the hope that it will be useful,
  11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13  * General Public License for more details.
  14  * 
  15  * You should have received a copy of the GNU General Public
  16  * License along with this library; if not, write to the Free Software
  17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  18  */
  19 
  20 #include <crm_internal.h>
  21 #include <crm/crm.h>
  22 
  23 #include <stdio.h>
  24 #include <sys/types.h>
  25 #include <unistd.h>
  26 
  27 #include <stdlib.h>
  28 #include <errno.h>
  29 #include <fcntl.h>
  30 
  31 #include <crm/transition.h>
  32 #include <crm/common/xml.h>
  33 #include <crm/common/util.h>
  34 #include <crm/msg_xml.h>
  35 
  36 #include <crm/cib.h>
  37 
  38 #include <glib.h>
  39 #include <pengine.h>
  40 #include <allocate.h>
  41 #if HAVE_LIBXML2
  42 #  include <libxml/parser.h>
  43 #endif
  44 
  45 gboolean use_stdin = FALSE;
  46 gboolean do_simulation = FALSE;
  47 gboolean inhibit_exit = FALSE;
  48 gboolean all_actions = FALSE;
  49 extern xmlNode *do_calculations(pe_working_set_t * data_set, xmlNode * xml_input, crm_time_t * now);
  50 extern void cleanup_calculations(pe_working_set_t * data_set);
  51 char *use_date = NULL;
  52 
  53 FILE *dot_strm = NULL;
  54 
  55 #define DOT_PREFIX "PE_DOT: "
  56 /* #define DOT_PREFIX "" */
  57 
  58 #define dot_write(fmt...) if(dot_strm != NULL) {        \
  59         fprintf(dot_strm, fmt);                         \
  60         fprintf(dot_strm, "\n");                        \
  61     } else {                                            \
  62         crm_debug(DOT_PREFIX""fmt);                     \
  63     }
  64 
  65 static void
  66 init_dotfile(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  67 {
  68     dot_write(" digraph \"g\" {");
  69 /*      dot_write("     size = \"30,30\""); */
  70 /*      dot_write("     graph ["); */
  71 /*      dot_write("             fontsize = \"12\""); */
  72 /*      dot_write("             fontname = \"Times-Roman\""); */
  73 /*      dot_write("             fontcolor = \"black\""); */
  74 /*      dot_write("             bb = \"0,0,398.922306,478.927856\""); */
  75 /*      dot_write("             color = \"black\""); */
  76 /*      dot_write("     ]"); */
  77 /*      dot_write("     node ["); */
  78 /*      dot_write("             fontsize = \"12\""); */
  79 /*      dot_write("             fontname = \"Times-Roman\""); */
  80 /*      dot_write("             fontcolor = \"black\""); */
  81 /*      dot_write("             shape = \"ellipse\""); */
  82 /*      dot_write("             color = \"black\""); */
  83 /*      dot_write("     ]"); */
  84 /*      dot_write("     edge ["); */
  85 /*      dot_write("             fontsize = \"12\""); */
  86 /*      dot_write("             fontname = \"Times-Roman\""); */
  87 /*      dot_write("             fontcolor = \"black\""); */
  88 /*      dot_write("             color = \"black\""); */
  89 /*      dot_write("     ]"); */
  90 }
  91 
  92 static char *
  93 create_action_name(action_t * action)
     /* [previous][next][first][last][top][bottom][index][help] */
  94 {
  95     char *action_name = NULL;
  96     const char *action_host = NULL;
  97 
  98     if (action->node) {
  99         action_host = action->node->details->uname;
 100         action_name = crm_concat(action->uuid, action_host, ' ');
 101 
 102     } else if (is_set(action->flags, pe_action_pseudo)) {
 103         action_name = strdup(action->uuid);
 104 
 105     } else {
 106         action_host = "<none>";
 107         action_name = crm_concat(action->uuid, action_host, ' ');
 108     }
 109     if (safe_str_eq(action->task, RSC_CANCEL)) {
 110         char *tmp_action_name = action_name;
 111 
 112         action_name = crm_concat("Cancel", tmp_action_name, ' ');
 113         free(tmp_action_name);
 114     }
 115 
 116     return action_name;
 117 }
 118 
 119 gboolean USE_LIVE_CIB = FALSE;
 120 /* *INDENT-OFF* */
 121 static struct crm_option long_options[] = {
 122     /* Top-level Options */
 123     {"help",           0, 0, '?', "This text"},
 124     {"version",        0, 0, '$', "Version information"  },
 125     {"verbose",        0, 0, 'V', "Increase debug output\n"},
 126 
 127     {"simulate",    0, 0, 'S', "Simulate the transition's execution to find invalid graphs\n"},
 128     {"show-scores", 0, 0, 's', "Display resource allocation scores"},
 129     {"show-utilization", 0, 0, 'U', "Display utilization information"},
 130     {"all-actions", 0, 0, 'a', "Display all possible actions - even ones not part of the transition graph"},
 131 
 132     {"live-check",  0, 0, 'L', "Connect to the CIB and use the current contents as input"},
 133     {"xml-text",    1, 0, 'X', "Retrieve XML from the supplied string"},
 134     {"xml-file",    1, 0, 'x', "Retrieve XML from the named file"},
 135     /* {"xml-pipe",    0, 0, 'p', "Retrieve XML from stdin\n"}, */
 136     
 137     {"save-input",  1, 0, 'I', "\tSave the input to the named file"},
 138     {"save-graph",  1, 0, 'G', "\tSave the transition graph (XML format) to the named file"},
 139     {"save-dotfile",1, 0, 'D', "Save the transition graph (DOT format) to the named file\n"},
 140     
 141     {0, 0, 0, 0}
 142 };
 143 /* *INDENT-ON* */
 144 
 145 int
 146 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 147 {
 148     GListPtr lpc = NULL;
 149     gboolean process = TRUE;
 150     gboolean all_good = TRUE;
 151     enum transition_status graph_rc = -1;
 152     crm_graph_t *transition = NULL;
 153     crm_time_t *a_date = NULL;
 154     cib_t *cib_conn = NULL;
 155 
 156     xmlNode *cib_object = NULL;
 157     int argerr = 0;
 158     int flag;
 159 
 160     char *msg_buffer = NULL;
 161     gboolean optional = FALSE;
 162     pe_working_set_t data_set;
 163 
 164     const char *source = NULL;
 165     const char *xml_file = NULL;
 166     const char *dot_file = NULL;
 167     const char *graph_file = NULL;
 168     const char *input_file = NULL;
 169     const char *input_xml = NULL;
 170 
 171     /* disable glib's fancy allocators that can't be free'd */
 172     GMemVTable vtable;
 173 
 174     vtable.malloc = malloc;
 175     vtable.realloc = realloc;
 176     vtable.free = free;
 177     vtable.calloc = calloc;
 178     vtable.try_malloc = malloc;
 179     vtable.try_realloc = realloc;
 180 
 181     g_mem_set_vtable(&vtable);
 182 
 183     crm_log_cli_init("ptest");
 184     crm_set_options(NULL, "[-?Vv] -[Xxp] {other options}", long_options,
 185                     "Calculate the cluster's response to the supplied cluster state\n"
 186                     "\nSuperseded by crm_simulate and likely to be removed in a future release\n\n");
 187 
 188     while (1) {
 189         int option_index = 0;
 190 
 191         flag = crm_get_option(argc, argv, &option_index);
 192         if (flag == -1)
 193             break;
 194 
 195         switch (flag) {
 196             case 'S':
 197                 do_simulation = TRUE;
 198                 break;
 199             case 'a':
 200                 all_actions = TRUE;
 201                 break;
 202             case 'w':
 203                 inhibit_exit = TRUE;
 204                 break;
 205             case 'X':
 206                 /*use_stdin = TRUE; */
 207                 input_xml = optarg;
 208                 break;
 209             case 's':
 210                 show_scores = TRUE;
 211                 break;
 212             case 'U':
 213                 show_utilization = TRUE;
 214                 break;
 215             case 'x':
 216                 xml_file = optarg;
 217                 break;
 218             case 'd':
 219                 use_date = optarg;
 220                 break;
 221             case 'D':
 222                 dot_file = optarg;
 223                 break;
 224             case 'G':
 225                 graph_file = optarg;
 226                 break;
 227             case 'I':
 228                 input_file = optarg;
 229                 break;
 230             case 'V':
 231                 crm_bump_log_level(argc, argv);
 232                 break;
 233             case 'L':
 234                 USE_LIVE_CIB = TRUE;
 235                 break;
 236             case '$':
 237             case '?':
 238                 crm_help(flag, 0);
 239                 break;
 240             default:
 241                 fprintf(stderr, "Option -%c is not yet supported\n", flag);
 242                 ++argerr;
 243                 break;
 244         }
 245     }
 246 
 247     if (optind < argc) {
 248         printf("non-option ARGV-elements: ");
 249         while (optind < argc) {
 250             printf("%s ", argv[optind++]);
 251         }
 252         printf("\n");
 253     }
 254 
 255     if (optind > argc) {
 256         ++argerr;
 257     }
 258 
 259     if (argerr) {
 260         crm_err("%d errors in option parsing", argerr);
 261         crm_help('?', 1);
 262     }
 263 
 264     if (USE_LIVE_CIB) {
 265         int rc = pcmk_ok;
 266 
 267         source = "live cib";
 268         cib_conn = cib_new();
 269         rc = cib_conn->cmds->signon(cib_conn, "ptest", cib_command);
 270 
 271         if (rc == pcmk_ok) {
 272             crm_info("Reading XML from: live cluster");
 273             cib_object = get_cib_copy(cib_conn);
 274 
 275         } else {
 276             fprintf(stderr, "Live CIB query failed: %s\n", pcmk_strerror(rc));
 277             return 3;
 278         }
 279         if (cib_object == NULL) {
 280             fprintf(stderr, "Live CIB query failed: empty result\n");
 281             return 3;
 282         }
 283 
 284     } else if (xml_file != NULL) {
 285         source = xml_file;
 286         cib_object = filename2xml(xml_file);
 287 
 288     } else if (use_stdin) {
 289         source = "stdin";
 290         cib_object = filename2xml(NULL);
 291     } else if (input_xml) {
 292         source = "input string";
 293         cib_object = string2xml(input_xml);
 294     }
 295 
 296     if (cib_object == NULL && source) {
 297         fprintf(stderr, "Could not parse configuration input from: %s\n", source);
 298         return 4;
 299 
 300     } else if (cib_object == NULL) {
 301         fprintf(stderr, "No configuration specified\n");
 302         crm_help('?', 1);
 303     }
 304 
 305     if (get_object_root(XML_CIB_TAG_STATUS, cib_object) == NULL) {
 306         create_xml_node(cib_object, XML_CIB_TAG_STATUS);
 307     }
 308 
 309     if (cli_config_update(&cib_object, NULL, FALSE) == FALSE) {
 310         free_xml(cib_object);
 311         return -ENOKEY;
 312     }
 313 
 314     if (validate_xml(cib_object, NULL, FALSE) != TRUE) {
 315         free_xml(cib_object);
 316         return -pcmk_err_schema_validation;
 317     }
 318 
 319     if (input_file != NULL) {
 320         FILE *input_strm = fopen(input_file, "w");
 321 
 322         if (input_strm == NULL) {
 323             crm_perror(LOG_ERR, "Could not open %s for writing", input_file);
 324         } else {
 325             msg_buffer = dump_xml_formatted(cib_object);
 326             if (fprintf(input_strm, "%s\n", msg_buffer) < 0) {
 327                 crm_perror(LOG_ERR, "Write to %s failed", input_file);
 328             }
 329             fflush(input_strm);
 330             fclose(input_strm);
 331             free(msg_buffer);
 332         }
 333     }
 334 
 335     if (use_date != NULL) {
 336         a_date = crm_time_new(use_date);
 337         crm_time_log(LOG_WARNING, "Set fake 'now' to", a_date,
 338                      crm_time_log_date | crm_time_log_timeofday);
 339         crm_time_log(LOG_WARNING, "Set fake 'now' to (localtime)", a_date,
 340                      crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone);
 341     }
 342 
 343     set_working_set_defaults(&data_set);
 344     if (process) {
 345         if (show_scores && show_utilization) {
 346             fprintf(stdout, "Allocation scores and utilization information:\n");
 347         } else if (show_scores) {
 348             fprintf(stdout, "Allocation scores:\n");
 349         } else if (show_utilization) {
 350             fprintf(stdout, "Utilization information:\n");
 351         }
 352         do_calculations(&data_set, cib_object, a_date);
 353     }
 354 
 355     msg_buffer = dump_xml_formatted(data_set.graph);
 356     if (safe_str_eq(graph_file, "-")) {
 357         fprintf(stdout, "%s\n", msg_buffer);
 358         fflush(stdout);
 359     } else if (graph_file != NULL) {
 360         FILE *graph_strm = fopen(graph_file, "w");
 361 
 362         if (graph_strm == NULL) {
 363             crm_perror(LOG_ERR, "Could not open %s for writing", graph_file);
 364         } else {
 365             if (fprintf(graph_strm, "%s\n\n", msg_buffer) < 0) {
 366                 crm_perror(LOG_ERR, "Write to %s failed", graph_file);
 367             }
 368             fflush(graph_strm);
 369             fclose(graph_strm);
 370         }
 371     }
 372     free(msg_buffer);
 373 
 374     if (dot_file != NULL) {
 375         dot_strm = fopen(dot_file, "w");
 376         if (dot_strm == NULL) {
 377             crm_perror(LOG_ERR, "Could not open %s for writing", dot_file);
 378         }
 379     }
 380 
 381     if (dot_strm == NULL) {
 382         goto simulate;
 383     }
 384 
 385     init_dotfile();
 386     for (lpc = data_set.actions; lpc != NULL; lpc = lpc->next) {
 387         action_t *action = (action_t *) lpc->data;
 388         const char *style = "filled";
 389         const char *font = "black";
 390         const char *color = "black";
 391         const char *fill = NULL;
 392         char *action_name = create_action_name(action);
 393 
 394         crm_trace("Action %d: %p", action->id, action);
 395 
 396         if (is_set(action->flags, pe_action_pseudo)) {
 397             font = "orange";
 398         }
 399 
 400         style = "dashed";
 401         if (is_set(action->flags, pe_action_dumped)) {
 402             style = "bold";
 403             color = "green";
 404 
 405         } else if (action->rsc != NULL && is_not_set(action->rsc->flags, pe_rsc_managed)) {
 406             color = "purple";
 407             if (all_actions == FALSE) {
 408                 goto dont_write;
 409             }
 410 
 411         } else if (is_set(action->flags, pe_action_optional)) {
 412             color = "blue";
 413             if (all_actions == FALSE) {
 414                 goto dont_write;
 415             }
 416 
 417         } else {
 418             color = "red";
 419             CRM_CHECK(is_set(action->flags, pe_action_runnable) == FALSE,;
 420                 );
 421         }
 422 
 423         set_bit(action->flags, pe_action_dumped);
 424         dot_write("\"%s\" [ style=%s color=\"%s\" fontcolor=\"%s\"  %s%s]",
 425                   action_name, style, color, font, fill ? "fillcolor=" : "", fill ? fill : "");
 426   dont_write:
 427         free(action_name);
 428     }
 429 
 430     for (lpc = data_set.actions; lpc != NULL; lpc = lpc->next) {
 431         action_t *action = (action_t *) lpc->data;
 432 
 433         GListPtr lpc2 = NULL;
 434 
 435         for (lpc2 = action->actions_before; lpc2 != NULL; lpc2 = lpc2->next) {
 436             action_wrapper_t *before = (action_wrapper_t *) lpc2->data;
 437 
 438             char *before_name = NULL;
 439             char *after_name = NULL;
 440             const char *style = "dashed";
 441 
 442             optional = TRUE;
 443             if (before->state == pe_link_dumped) {
 444                 optional = FALSE;
 445                 style = "bold";
 446             } else if (is_set(action->flags, pe_action_pseudo)
 447                        && (before->type & pe_order_stonith_stop)) {
 448                 continue;
 449             } else if (before->state == pe_link_dup) {
 450                 continue;
 451             } else if (before->type == pe_order_none) {
 452                 continue;
 453             } else if (is_set(before->action->flags, pe_action_dumped)
 454                        && is_set(action->flags, pe_action_dumped)) {
 455                 optional = FALSE;
 456             }
 457 
 458             if (all_actions || optional == FALSE) {
 459                 before_name = create_action_name(before->action);
 460                 after_name = create_action_name(action);
 461                 dot_write("\"%s\" -> \"%s\" [ style = %s]", before_name, after_name, style);
 462                 free(before_name);
 463                 free(after_name);
 464             }
 465         }
 466     }
 467     dot_write("}");
 468     if (dot_strm != NULL) {
 469         fflush(dot_strm);
 470         fclose(dot_strm);
 471     }
 472 
 473   simulate:
 474 
 475     if (do_simulation == FALSE) {
 476         goto cleanup;
 477     }
 478 
 479     transition = unpack_graph(data_set.graph, "ptest");
 480     print_graph(LOG_DEBUG, transition);
 481 
 482     do {
 483         graph_rc = run_graph(transition);
 484 
 485     } while (graph_rc == transition_active);
 486 
 487     if (graph_rc != transition_complete) {
 488         crm_crit("Transition failed: %s", transition_status(graph_rc));
 489         print_graph(LOG_ERR, transition);
 490     }
 491     destroy_graph(transition);
 492     CRM_CHECK(graph_rc == transition_complete, all_good = FALSE;
 493               crm_err("An invalid transition was produced"));
 494 
 495   cleanup:
 496     cleanup_alloc_calculations(&data_set);
 497     crm_log_deinit();
 498 
 499     /* required for MallocDebug.app */
 500     if (inhibit_exit) {
 501         GMainLoop *mainloop = g_main_new(FALSE);
 502 
 503         g_main_run(mainloop);
 504     }
 505 
 506     if (all_good) {
 507         return 0;
 508     }
 509     return graph_rc;
 510 }

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