This source file includes following definitions.
- get_date
- print_cluster_status
- create_action_name
- create_dotfile
- setup_input
- profile_one
- profile_all
- count_resources
- main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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)
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)
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
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)
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";
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)
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)
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
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
457 static struct crm_option long_options[] = {
458
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
515
516 static void
517 profile_one(const char *xml_file)
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)
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)
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)
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
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;
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 }