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