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