This source file includes following definitions.
- init_dotfile
- create_action_name
- main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
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)
67 {
68 dot_write(" digraph \"g\" {");
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 }
91
92 static char *
93 create_action_name(action_t * action)
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
121 static struct crm_option long_options[] = {
122
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
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
144
145 int
146 main(int argc, char **argv)
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
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
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
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 }