This source file includes following definitions.
- inject_transient_attr
- update_failcounts
- create_node_entry
- create_op
- inject_op
- inject_node_state
- modify_node
- find_resource_xml
- inject_resource
- find_ticket_state
- set_ticket_state_attr
- modify_configuration
- exec_pseudo_action
- exec_rsc_action
- exec_crmd_action
- exec_stonith_action
- run_simulation
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 static bool fake_quiet = FALSE;
40 static cib_t *fake_cib = NULL;
41 static GListPtr fake_resource_list = NULL;
42 static GListPtr fake_op_fail_list = NULL;
43 gboolean bringing_nodes_online = FALSE;
44
45 #define STATUS_PATH_MAX 512
46
47 #define quiet_log(fmt, args...) do { \
48 if(fake_quiet) { \
49 crm_trace(fmt, ##args); \
50 } else { \
51 printf(fmt , ##args); \
52 } \
53 } while(0)
54
55 #define new_node_template "//"XML_CIB_TAG_NODE"[@uname='%s']"
56 #define node_template "//"XML_CIB_TAG_STATE"[@uname='%s']"
57 #define rsc_template "//"XML_CIB_TAG_STATE"[@uname='%s']//"XML_LRM_TAG_RESOURCE"[@id='%s']"
58 #define op_template "//"XML_CIB_TAG_STATE"[@uname='%s']//"XML_LRM_TAG_RESOURCE"[@id='%s']/"XML_LRM_TAG_RSC_OP"[@id='%s']"
59
60
61
62 static void
63 inject_transient_attr(xmlNode * cib_node, const char *name, const char *value)
64 {
65 xmlNode *attrs = NULL;
66 xmlNode *instance_attrs = NULL;
67 xmlChar *node_path;
68 const char *node_uuid = ID(cib_node);
69
70 node_path = xmlGetNodePath(cib_node);
71 quiet_log(" + Injecting attribute %s=%s into %s '%s'\n",
72 name, value, node_path, ID(cib_node));
73 free(node_path);
74
75 attrs = first_named_child(cib_node, XML_TAG_TRANSIENT_NODEATTRS);
76 if (attrs == NULL) {
77 attrs = create_xml_node(cib_node, XML_TAG_TRANSIENT_NODEATTRS);
78 crm_xml_add(attrs, XML_ATTR_ID, node_uuid);
79 }
80
81 instance_attrs = first_named_child(attrs, XML_TAG_ATTR_SETS);
82 if (instance_attrs == NULL) {
83 instance_attrs = create_xml_node(attrs, XML_TAG_ATTR_SETS);
84 crm_xml_add(instance_attrs, XML_ATTR_ID, node_uuid);
85 }
86
87 crm_create_nvpair_xml(instance_attrs, NULL, name, value);
88 }
89
90 static void
91 update_failcounts(xmlNode * cib_node, const char *resource, const char *task,
92 int interval, int rc)
93 {
94 if (rc == 0) {
95 return;
96
97 } else if (rc == 7 && interval == 0) {
98 return;
99
100 } else {
101 char *name = NULL;
102 char *now = crm_itoa(time(NULL));
103
104 name = crm_failcount_name(resource, task, interval);
105 inject_transient_attr(cib_node, name, "value++");
106 free(name);
107
108 name = crm_lastfailure_name(resource, task, interval);
109 inject_transient_attr(cib_node, name, now);
110 free(name);
111 free(now);
112 }
113 }
114
115 static void
116 create_node_entry(cib_t * cib_conn, const char *node)
117 {
118 int rc = pcmk_ok;
119 int max = strlen(new_node_template) + strlen(node) + 1;
120 char *xpath = NULL;
121
122 xpath = calloc(1, max);
123
124 snprintf(xpath, max, new_node_template, node);
125 rc = cib_conn->cmds->query(cib_conn, xpath, NULL, cib_xpath | cib_sync_call | cib_scope_local);
126
127 if (rc == -ENXIO) {
128 xmlNode *cib_object = create_xml_node(NULL, XML_CIB_TAG_NODE);
129
130
131 crm_xml_add(cib_object, XML_ATTR_ID, node);
132 crm_xml_add(cib_object, XML_ATTR_UNAME, node);
133 cib_conn->cmds->create(cib_conn, XML_CIB_TAG_NODES, cib_object,
134 cib_sync_call | cib_scope_local);
135
136
137
138 free_xml(cib_object);
139 }
140
141 free(xpath);
142 }
143
144 static lrmd_event_data_t *
145 create_op(xmlNode * cib_resource, const char *task, int interval, int outcome)
146 {
147 lrmd_event_data_t *op = NULL;
148 xmlNode *xop = NULL;
149
150 op = calloc(1, sizeof(lrmd_event_data_t));
151
152 op->rsc_id = strdup(ID(cib_resource));
153 op->interval = interval;
154 op->op_type = strdup(task);
155
156 op->rc = outcome;
157 op->op_status = 0;
158 op->params = NULL;
159 op->t_run = time(NULL);
160 op->t_rcchange = op->t_run;
161
162 op->call_id = 0;
163 for (xop = __xml_first_child(cib_resource); xop != NULL; xop = __xml_next(xop)) {
164 int tmp = 0;
165
166 crm_element_value_int(xop, XML_LRM_ATTR_CALLID, &tmp);
167 if (tmp > op->call_id) {
168 op->call_id = tmp;
169 }
170 }
171 op->call_id++;
172
173 return op;
174 }
175
176 static xmlNode *
177 inject_op(xmlNode * cib_resource, lrmd_event_data_t * op, int target_rc)
178 {
179 return create_operation_update(cib_resource, op, CRM_FEATURE_SET, target_rc, NULL, crm_system_name,
180 LOG_DEBUG_2);
181 }
182
183 static xmlNode *
184 inject_node_state(cib_t * cib_conn, const char *node, const char *uuid)
185 {
186 int rc = pcmk_ok;
187 xmlNode *cib_object = NULL;
188 char *xpath = crm_strdup_printf(node_template, node);
189
190 if (bringing_nodes_online) {
191 create_node_entry(cib_conn, node);
192 }
193
194 rc = cib_conn->cmds->query(cib_conn, xpath, &cib_object,
195 cib_xpath | cib_sync_call | cib_scope_local);
196
197 if (cib_object && ID(cib_object) == NULL) {
198 crm_err("Detected multiple node_state entries for xpath=%s, bailing", xpath);
199 crm_log_xml_warn(cib_object, "Duplicates");
200 free(xpath);
201 crm_exit(ENOTUNIQ);
202 return NULL;
203 }
204
205 if (rc == -ENXIO) {
206 char *found_uuid = NULL;
207
208 if (uuid == NULL) {
209 query_node_uuid(cib_conn, node, &found_uuid, NULL);
210 } else {
211 found_uuid = strdup(uuid);
212 }
213
214 cib_object = create_xml_node(NULL, XML_CIB_TAG_STATE);
215 crm_xml_add(cib_object, XML_ATTR_UUID, found_uuid);
216 crm_xml_add(cib_object, XML_ATTR_UNAME, node);
217 cib_conn->cmds->create(cib_conn, XML_CIB_TAG_STATUS, cib_object,
218 cib_sync_call | cib_scope_local);
219 free_xml(cib_object);
220 free(found_uuid);
221
222 rc = cib_conn->cmds->query(cib_conn, xpath, &cib_object,
223 cib_xpath | cib_sync_call | cib_scope_local);
224 crm_trace("injecting node state for %s. rc is %d", node, rc);
225 }
226
227 free(xpath);
228 CRM_ASSERT(rc == pcmk_ok);
229 return cib_object;
230 }
231
232 static xmlNode *
233 modify_node(cib_t * cib_conn, char *node, gboolean up)
234 {
235 xmlNode *cib_node = inject_node_state(cib_conn, node, NULL);
236
237 if (up) {
238 crm_xml_add(cib_node, XML_NODE_IN_CLUSTER, XML_BOOLEAN_YES);
239 crm_xml_add(cib_node, XML_NODE_IS_PEER, ONLINESTATUS);
240 crm_xml_add(cib_node, XML_NODE_JOIN_STATE, CRMD_JOINSTATE_MEMBER);
241 crm_xml_add(cib_node, XML_NODE_EXPECTED, CRMD_JOINSTATE_MEMBER);
242
243 } else {
244 crm_xml_add(cib_node, XML_NODE_IN_CLUSTER, XML_BOOLEAN_NO);
245 crm_xml_add(cib_node, XML_NODE_IS_PEER, OFFLINESTATUS);
246 crm_xml_add(cib_node, XML_NODE_JOIN_STATE, CRMD_JOINSTATE_DOWN);
247 crm_xml_add(cib_node, XML_NODE_EXPECTED, CRMD_JOINSTATE_DOWN);
248 }
249
250 crm_xml_add(cib_node, XML_ATTR_ORIGIN, crm_system_name);
251 return cib_node;
252 }
253
254 static xmlNode *
255 find_resource_xml(xmlNode * cib_node, const char *resource)
256 {
257 char *xpath = NULL;
258 xmlNode *match = NULL;
259 const char *node = crm_element_value(cib_node, XML_ATTR_UNAME);
260 int max = strlen(rsc_template) + strlen(node) + strlen(resource) + 1;
261
262 xpath = calloc(1, max);
263
264 snprintf(xpath, max, rsc_template, node, resource);
265 match = get_xpath_object(xpath, cib_node, LOG_DEBUG_2);
266
267 free(xpath);
268 return match;
269 }
270
271
272 static xmlNode *
273 inject_resource(xmlNode * cib_node, const char *resource, const char *rclass, const char *rtype,
274 const char *rprovider)
275 {
276 xmlNode *lrm = NULL;
277 xmlNode *container = NULL;
278 xmlNode *cib_resource = NULL;
279 char *xpath = NULL;
280
281 cib_resource = find_resource_xml(cib_node, resource);
282 if (cib_resource != NULL) {
283 return cib_resource;
284 }
285
286
287
288 if (rclass == NULL || rtype == NULL) {
289 fprintf(stderr, "Resource %s not found in the status section of %s."
290 " Please supply the class and type to continue\n", resource, ID(cib_node));
291 return NULL;
292
293 } else if (safe_str_neq(rclass, PCMK_RESOURCE_CLASS_OCF)
294 && safe_str_neq(rclass, PCMK_RESOURCE_CLASS_STONITH)
295 && safe_str_neq(rclass, PCMK_RESOURCE_CLASS_HB)
296 && safe_str_neq(rclass, PCMK_RESOURCE_CLASS_SERVICE)
297 && safe_str_neq(rclass, PCMK_RESOURCE_CLASS_UPSTART)
298 && safe_str_neq(rclass, PCMK_RESOURCE_CLASS_SYSTEMD)
299 && safe_str_neq(rclass, PCMK_RESOURCE_CLASS_LSB)) {
300 fprintf(stderr, "Invalid class for %s: %s\n", resource, rclass);
301 return NULL;
302
303 } else if (crm_provider_required(rclass) && (rprovider == NULL)) {
304 fprintf(stderr, "Please specify the provider for resource %s\n", resource);
305 return NULL;
306 }
307
308 xpath = (char *)xmlGetNodePath(cib_node);
309 crm_info("Injecting new resource %s into %s '%s'", resource, xpath, ID(cib_node));
310 free(xpath);
311
312 lrm = first_named_child(cib_node, XML_CIB_TAG_LRM);
313 if (lrm == NULL) {
314 const char *node_uuid = ID(cib_node);
315
316 lrm = create_xml_node(cib_node, XML_CIB_TAG_LRM);
317 crm_xml_add(lrm, XML_ATTR_ID, node_uuid);
318 }
319
320 container = first_named_child(lrm, XML_LRM_TAG_RESOURCES);
321 if (container == NULL) {
322 container = create_xml_node(lrm, XML_LRM_TAG_RESOURCES);
323 }
324
325 cib_resource = create_xml_node(container, XML_LRM_TAG_RESOURCE);
326 crm_xml_add(cib_resource, XML_ATTR_ID, resource);
327
328 crm_xml_add(cib_resource, XML_AGENT_ATTR_CLASS, rclass);
329 crm_xml_add(cib_resource, XML_AGENT_ATTR_PROVIDER, rprovider);
330 crm_xml_add(cib_resource, XML_ATTR_TYPE, rtype);
331
332 return cib_resource;
333 }
334
335 #define XPATH_MAX 1024
336
337 static int
338 find_ticket_state(cib_t * the_cib, const char *ticket_id, xmlNode ** ticket_state_xml)
339 {
340 int offset = 0;
341 int rc = pcmk_ok;
342 xmlNode *xml_search = NULL;
343
344 char *xpath_string = NULL;
345
346 CRM_ASSERT(ticket_state_xml != NULL);
347 *ticket_state_xml = NULL;
348
349 xpath_string = calloc(1, XPATH_MAX);
350 offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "%s", "/cib/status/tickets");
351
352 if (ticket_id) {
353 offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "/%s[@id=\"%s\"]",
354 XML_CIB_TAG_TICKET_STATE, ticket_id);
355 }
356 CRM_LOG_ASSERT(offset > 0);
357 rc = the_cib->cmds->query(the_cib, xpath_string, &xml_search,
358 cib_sync_call | cib_scope_local | cib_xpath);
359
360 if (rc != pcmk_ok) {
361 goto bail;
362 }
363
364 crm_log_xml_debug(xml_search, "Match");
365 if (xml_has_children(xml_search)) {
366 if (ticket_id) {
367 fprintf(stdout, "Multiple ticket_states match ticket_id=%s\n", ticket_id);
368 }
369 *ticket_state_xml = xml_search;
370 } else {
371 *ticket_state_xml = xml_search;
372 }
373
374 bail:
375 free(xpath_string);
376 return rc;
377 }
378
379 static int
380 set_ticket_state_attr(const char *ticket_id, const char *attr_name,
381 const char *attr_value, cib_t * cib, int cib_options)
382 {
383 int rc = pcmk_ok;
384 xmlNode *xml_top = NULL;
385 xmlNode *ticket_state_xml = NULL;
386
387 rc = find_ticket_state(cib, ticket_id, &ticket_state_xml);
388 if (rc == pcmk_ok) {
389 crm_debug("Found a match state for ticket: id=%s", ticket_id);
390 xml_top = ticket_state_xml;
391
392 } else if (rc != -ENXIO) {
393 return rc;
394
395 } else {
396 xmlNode *xml_obj = NULL;
397
398 xml_top = create_xml_node(NULL, XML_CIB_TAG_STATUS);
399 xml_obj = create_xml_node(xml_top, XML_CIB_TAG_TICKETS);
400 ticket_state_xml = create_xml_node(xml_obj, XML_CIB_TAG_TICKET_STATE);
401 crm_xml_add(ticket_state_xml, XML_ATTR_ID, ticket_id);
402 }
403
404 crm_xml_add(ticket_state_xml, attr_name, attr_value);
405
406 crm_log_xml_debug(xml_top, "Update");
407
408 rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, xml_top, cib_options);
409
410 free_xml(xml_top);
411
412 return rc;
413 }
414
415 void
416 modify_configuration(pe_working_set_t * data_set, cib_t *cib,
417 const char *quorum, const char *watchdog, GListPtr node_up, GListPtr node_down, GListPtr node_fail,
418 GListPtr op_inject, GListPtr ticket_grant, GListPtr ticket_revoke,
419 GListPtr ticket_standby, GListPtr ticket_activate)
420 {
421 int rc = pcmk_ok;
422 GListPtr gIter = NULL;
423
424 xmlNode *cib_op = NULL;
425 xmlNode *cib_node = NULL;
426 xmlNode *cib_resource = NULL;
427
428 lrmd_event_data_t *op = NULL;
429
430 if (quorum) {
431 xmlNode *top = create_xml_node(NULL, XML_TAG_CIB);
432
433 quiet_log(" + Setting quorum: %s\n", quorum);
434
435 crm_xml_add(top, XML_ATTR_HAVE_QUORUM, quorum);
436
437 rc = cib->cmds->modify(cib, NULL, top, cib_sync_call | cib_scope_local);
438 CRM_ASSERT(rc == pcmk_ok);
439 }
440
441 if (watchdog) {
442 quiet_log(" + Setting watchdog: %s\n", watchdog);
443
444 rc = update_attr_delegate(cib, cib_sync_call | cib_scope_local,
445 XML_CIB_TAG_CRMCONFIG, NULL, NULL, NULL, NULL,
446 XML_ATTR_HAVE_WATCHDOG, watchdog, FALSE, NULL, NULL);
447
448 CRM_ASSERT(rc == pcmk_ok);
449 }
450
451 for (gIter = node_up; gIter != NULL; gIter = gIter->next) {
452 char *node = (char *)gIter->data;
453
454 quiet_log(" + Bringing node %s online\n", node);
455 cib_node = modify_node(cib, node, TRUE);
456 CRM_ASSERT(cib_node != NULL);
457
458 rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node,
459 cib_sync_call | cib_scope_local);
460 CRM_ASSERT(rc == pcmk_ok);
461 free_xml(cib_node);
462 }
463
464 for (gIter = node_down; gIter != NULL; gIter = gIter->next) {
465 char xpath[STATUS_PATH_MAX];
466 char *node = (char *)gIter->data;
467
468 quiet_log(" + Taking node %s offline\n", node);
469 cib_node = modify_node(cib, node, FALSE);
470 CRM_ASSERT(cib_node != NULL);
471
472 rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node,
473 cib_sync_call | cib_scope_local);
474 CRM_ASSERT(rc == pcmk_ok);
475 free_xml(cib_node);
476
477 snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", node, XML_CIB_TAG_LRM);
478 cib->cmds->delete(cib, xpath, NULL,
479 cib_xpath | cib_sync_call | cib_scope_local);
480
481 snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", node,
482 XML_TAG_TRANSIENT_NODEATTRS);
483 cib->cmds->delete(cib, xpath, NULL,
484 cib_xpath | cib_sync_call | cib_scope_local);
485
486 }
487
488 for (gIter = node_fail; gIter != NULL; gIter = gIter->next) {
489 char *node = (char *)gIter->data;
490
491 quiet_log(" + Failing node %s\n", node);
492 cib_node = modify_node(cib, node, TRUE);
493 crm_xml_add(cib_node, XML_NODE_IN_CLUSTER, XML_BOOLEAN_NO);
494 CRM_ASSERT(cib_node != NULL);
495
496 rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node,
497 cib_sync_call | cib_scope_local);
498 CRM_ASSERT(rc == pcmk_ok);
499 free_xml(cib_node);
500 }
501
502 for (gIter = ticket_grant; gIter != NULL; gIter = gIter->next) {
503 char *ticket_id = (char *)gIter->data;
504
505 quiet_log(" + Granting ticket %s\n", ticket_id);
506 rc = set_ticket_state_attr(ticket_id, "granted", "true",
507 cib, cib_sync_call | cib_scope_local);
508
509 CRM_ASSERT(rc == pcmk_ok);
510 }
511
512 for (gIter = ticket_revoke; gIter != NULL; gIter = gIter->next) {
513 char *ticket_id = (char *)gIter->data;
514
515 quiet_log(" + Revoking ticket %s\n", ticket_id);
516 rc = set_ticket_state_attr(ticket_id, "granted", "false",
517 cib, cib_sync_call | cib_scope_local);
518
519 CRM_ASSERT(rc == pcmk_ok);
520 }
521
522 for (gIter = ticket_standby; gIter != NULL; gIter = gIter->next) {
523 char *ticket_id = (char *)gIter->data;
524
525 quiet_log(" + Making ticket %s standby\n", ticket_id);
526 rc = set_ticket_state_attr(ticket_id, "standby", "true",
527 cib, cib_sync_call | cib_scope_local);
528
529 CRM_ASSERT(rc == pcmk_ok);
530 }
531
532 for (gIter = ticket_activate; gIter != NULL; gIter = gIter->next) {
533 char *ticket_id = (char *)gIter->data;
534
535 quiet_log(" + Activating ticket %s\n", ticket_id);
536 rc = set_ticket_state_attr(ticket_id, "standby", "false",
537 cib, cib_sync_call | cib_scope_local);
538
539 CRM_ASSERT(rc == pcmk_ok);
540 }
541
542 for (gIter = op_inject; gIter != NULL; gIter = gIter->next) {
543 char *spec = (char *)gIter->data;
544
545 int rc = 0;
546 int outcome = 0;
547 int interval = 0;
548
549 char *key = NULL;
550 char *node = NULL;
551 char *task = NULL;
552 char *resource = NULL;
553
554 const char *rtype = NULL;
555 const char *rclass = NULL;
556 const char *rprovider = NULL;
557
558 resource_t *rsc = NULL;
559
560 quiet_log(" + Injecting %s into the configuration\n", spec);
561
562 key = calloc(1, strlen(spec) + 1);
563 node = calloc(1, strlen(spec) + 1);
564 rc = sscanf(spec, "%[^@]@%[^=]=%d", key, node, &outcome);
565 if (rc != 3) {
566 fprintf(stderr, "Invalid operation spec: %s. Only found %d fields\n", spec, rc);
567 free(key);
568 free(node);
569 continue;
570 }
571
572 parse_op_key(key, &resource, &task, &interval);
573
574 rsc = pe_find_resource(data_set->resources, resource);
575 if (rsc == NULL) {
576 fprintf(stderr, " - Invalid resource name: %s\n", resource);
577 } else {
578 rclass = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
579 rtype = crm_element_value(rsc->xml, XML_ATTR_TYPE);
580 rprovider = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
581
582 cib_node = inject_node_state(cib, node, NULL);
583 CRM_ASSERT(cib_node != NULL);
584
585 update_failcounts(cib_node, resource, task, interval, outcome);
586
587 cib_resource = inject_resource(cib_node, resource, rclass, rtype, rprovider);
588 CRM_ASSERT(cib_resource != NULL);
589
590 op = create_op(cib_resource, task, interval, outcome);
591 CRM_ASSERT(op != NULL);
592
593 cib_op = inject_op(cib_resource, op, 0);
594 CRM_ASSERT(cib_op != NULL);
595 lrmd_free_event(op);
596
597 rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node,
598 cib_sync_call | cib_scope_local);
599 CRM_ASSERT(rc == pcmk_ok);
600 }
601 free(task);
602 free(node);
603 free(key);
604 }
605 }
606
607 static gboolean
608 exec_pseudo_action(crm_graph_t * graph, crm_action_t * action)
609 {
610 const char *node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
611 const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY);
612
613 action->confirmed = TRUE;
614
615 quiet_log(" * Pseudo action: %s%s%s\n", task, node ? " on " : "", node ? node : "");
616 update_graph(graph, action);
617 return TRUE;
618 }
619
620 static gboolean
621 exec_rsc_action(crm_graph_t * graph, crm_action_t * action)
622 {
623 int rc = 0;
624 GListPtr gIter = NULL;
625 lrmd_event_data_t *op = NULL;
626 int target_outcome = 0;
627 gboolean uname_is_uuid = FALSE;
628
629 const char *rtype = NULL;
630 const char *rclass = NULL;
631 const char *resource = NULL;
632 const char *rprovider = NULL;
633 const char *operation = crm_element_value(action->xml, "operation");
634 const char *target_rc_s = crm_meta_value(action->params, XML_ATTR_TE_TARGET_RC);
635
636 xmlNode *cib_node = NULL;
637 xmlNode *cib_resource = NULL;
638 xmlNode *action_rsc = first_named_child(action->xml, XML_CIB_TAG_RESOURCE);
639
640 char *node = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET);
641 char *uuid = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET_UUID);
642 const char *router_node = crm_element_value(action->xml, XML_LRM_ATTR_ROUTER_NODE);
643
644 if (safe_str_eq(operation, CRM_OP_PROBED)
645 || safe_str_eq(operation, CRM_OP_REPROBE)) {
646 crm_info("Skipping %s op for %s", operation, node);
647 goto done;
648 }
649
650 if (action_rsc == NULL) {
651 crm_log_xml_err(action->xml, "Bad");
652 free(node); free(uuid);
653 return FALSE;
654 }
655
656
657
658
659
660 resource = crm_element_value(action_rsc, XML_ATTR_ID);
661 if (pe_find_resource(fake_resource_list, resource) == NULL) {
662 const char *longname = crm_element_value(action_rsc, XML_ATTR_ID_LONG);
663
664 if (pe_find_resource(fake_resource_list, longname)) {
665 resource = longname;
666 }
667 }
668
669 if (safe_str_eq(operation, "delete") || safe_str_eq(operation, RSC_METADATA)) {
670 quiet_log(" * Resource action: %-15s %s on %s\n", resource, operation, node);
671 goto done;
672 }
673
674 rclass = crm_element_value(action_rsc, XML_AGENT_ATTR_CLASS);
675 rtype = crm_element_value(action_rsc, XML_ATTR_TYPE);
676 rprovider = crm_element_value(action_rsc, XML_AGENT_ATTR_PROVIDER);
677
678 if (target_rc_s != NULL) {
679 target_outcome = crm_parse_int(target_rc_s, "0");
680 }
681
682 CRM_ASSERT(fake_cib->cmds->query(fake_cib, NULL, NULL, cib_sync_call | cib_scope_local) ==
683 pcmk_ok);
684
685 if (router_node) {
686 uname_is_uuid = TRUE;
687 }
688
689 cib_node = inject_node_state(fake_cib, node, uname_is_uuid ? node : uuid);
690 CRM_ASSERT(cib_node != NULL);
691
692 cib_resource = inject_resource(cib_node, resource, rclass, rtype, rprovider);
693 CRM_ASSERT(cib_resource != NULL);
694
695 op = convert_graph_action(cib_resource, action, 0, target_outcome);
696 if (op->interval) {
697 quiet_log(" * Resource action: %-15s %s=%d on %s\n", resource, op->op_type, op->interval,
698 node);
699 } else {
700 quiet_log(" * Resource action: %-15s %s on %s\n", resource, op->op_type, node);
701 }
702
703 for (gIter = fake_op_fail_list; gIter != NULL; gIter = gIter->next) {
704 char *spec = (char *)gIter->data;
705 char *key = NULL;
706
707 key = calloc(1, 1 + strlen(spec));
708 snprintf(key, strlen(spec), "%s_%s_%d@%s=", resource, op->op_type, op->interval, node);
709
710 if (strncasecmp(key, spec, strlen(key)) == 0) {
711 rc = sscanf(spec, "%*[^=]=%d", (int *) &op->rc);
712
713
714 if (rc != 1) {
715 fprintf(stderr,
716 "Invalid failed operation spec: %s. Result code must be integer\n",
717 spec);
718 free(key);
719 continue;
720 }
721 action->failed = TRUE;
722 graph->abort_priority = INFINITY;
723 printf("\tPretending action %d failed with rc=%d\n", action->id, op->rc);
724 update_failcounts(cib_node, resource, op->op_type, op->interval, op->rc);
725 free(key);
726 break;
727 }
728 free(key);
729 }
730
731 inject_op(cib_resource, op, target_outcome);
732 lrmd_free_event(op);
733
734 rc = fake_cib->cmds->modify(fake_cib, XML_CIB_TAG_STATUS, cib_node,
735 cib_sync_call | cib_scope_local);
736 CRM_ASSERT(rc == pcmk_ok);
737
738 done:
739 free(node); free(uuid);
740 free_xml(cib_node);
741 action->confirmed = TRUE;
742 update_graph(graph, action);
743 return TRUE;
744 }
745
746 static gboolean
747 exec_crmd_action(crm_graph_t * graph, crm_action_t * action)
748 {
749 const char *node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
750 const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
751 xmlNode *rsc = first_named_child(action->xml, XML_CIB_TAG_RESOURCE);
752
753 action->confirmed = TRUE;
754
755 if(rsc) {
756 quiet_log(" * Cluster action: %s for %s on %s\n", task, ID(rsc), node);
757 } else {
758 quiet_log(" * Cluster action: %s on %s\n", task, node);
759 }
760 update_graph(graph, action);
761 return TRUE;
762 }
763
764 static gboolean
765 exec_stonith_action(crm_graph_t * graph, crm_action_t * action)
766 {
767 const char *op = crm_meta_value(action->params, "stonith_action");
768 char *target = crm_element_value_copy(action->xml, XML_LRM_ATTR_TARGET);
769
770 quiet_log(" * Fencing %s (%s)\n", target, op);
771 if(safe_str_neq(op, "on")) {
772 int rc = 0;
773 char xpath[STATUS_PATH_MAX];
774 xmlNode *cib_node = modify_node(fake_cib, target, FALSE);
775
776 crm_xml_add(cib_node, XML_ATTR_ORIGIN, __FUNCTION__);
777 CRM_ASSERT(cib_node != NULL);
778
779 rc = fake_cib->cmds->replace(fake_cib, XML_CIB_TAG_STATUS, cib_node,
780 cib_sync_call | cib_scope_local);
781 CRM_ASSERT(rc == pcmk_ok);
782
783 snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", target, XML_CIB_TAG_LRM);
784 fake_cib->cmds->delete(fake_cib, xpath, NULL,
785 cib_xpath | cib_sync_call | cib_scope_local);
786
787 snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", target,
788 XML_TAG_TRANSIENT_NODEATTRS);
789 fake_cib->cmds->delete(fake_cib, xpath, NULL,
790 cib_xpath | cib_sync_call | cib_scope_local);
791
792 free_xml(cib_node);
793 }
794
795 action->confirmed = TRUE;
796 update_graph(graph, action);
797 free(target);
798 return TRUE;
799 }
800
801 int
802 run_simulation(pe_working_set_t * data_set, cib_t *cib, GListPtr op_fail_list, bool quiet)
803 {
804 crm_graph_t *transition = NULL;
805 enum transition_status graph_rc = -1;
806
807 crm_graph_functions_t exec_fns = {
808 exec_pseudo_action,
809 exec_rsc_action,
810 exec_crmd_action,
811 exec_stonith_action,
812 };
813
814 fake_cib = cib;
815 fake_quiet = quiet;
816 fake_op_fail_list = op_fail_list;
817
818 quiet_log("\nExecuting cluster transition:\n");
819
820 set_graph_functions(&exec_fns);
821 transition = unpack_graph(data_set->graph, crm_system_name);
822 print_graph(LOG_DEBUG, transition);
823
824 fake_resource_list = data_set->resources;
825 do {
826 graph_rc = run_graph(transition);
827
828 } while (graph_rc == transition_active);
829 fake_resource_list = NULL;
830
831 if (graph_rc != transition_complete) {
832 fprintf(stdout, "Transition failed: %s\n", transition_status(graph_rc));
833 print_graph(LOG_ERR, transition);
834 }
835 destroy_graph(transition);
836 if (graph_rc != transition_complete) {
837 fprintf(stdout, "An invalid transition was produced\n");
838 }
839
840 if (quiet == FALSE) {
841 xmlNode *cib_object = NULL;
842 int rc = fake_cib->cmds->query(fake_cib, NULL, &cib_object, cib_sync_call | cib_scope_local);
843
844 CRM_ASSERT(rc == pcmk_ok);
845 cleanup_alloc_calculations(data_set);
846 data_set->input = cib_object;
847 }
848
849 if (graph_rc != transition_complete) {
850 return graph_rc;
851 }
852 return 0;
853 }