pacemaker 2.1.1-77db578727
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
pcmk_sched_transition.c
Go to the documentation of this file.
1/*
2 * Copyright 2009-2021 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU General Public License version 2
7 * or later (GPLv2+) WITHOUT ANY WARRANTY.
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> // lrmd_event_data_t, lrmd_free_event()
23#include <crm/cib.h>
24#include <crm/common/util.h>
25#include <crm/common/iso8601.h>
27#include <crm/pengine/status.h>
28#include <pacemaker-internal.h>
29
30static pcmk__output_t *out = NULL;
31static cib_t *fake_cib = NULL;
32static GList *fake_resource_list = NULL;
33static GList *fake_op_fail_list = NULL;
34gboolean 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
43static void
44inject_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
53 if (attrs == NULL) {
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
67static void
68update_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
92static void
93create_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); // Use node name as ID
104 crm_xml_add(cib_object, XML_ATTR_UNAME, node);
105 cib_conn->cmds->create(cib_conn, XML_CIB_TAG_NODES, cib_object,
107 /* Not bothering with subsequent query to see if it exists,
108 we'll bomb out later in the call to query_node_uuid()... */
109
110 free_xml(cib_object);
111 }
112
113 free(xpath);
114}
115
116static lrmd_event_data_t *
117create_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; /* TODO: Fill me in */
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
137 if (tmp > op->call_id) {
138 op->call_id = tmp;
139 }
140 }
141 op->call_id++;
142
143 return op;
144}
145
146static xmlNode *
147inject_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
154static xmlNode *
155inject_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
162 create_node_entry(cib_conn, node);
163 }
164
165 rc = cib_conn->cmds->query(cib_conn, xpath, &cib_object,
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);
173 return NULL; // not reached, but makes static analysis happy
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,
190 free_xml(cib_object);
191 free(found_uuid);
192
193 rc = cib_conn->cmds->query(cib_conn, xpath, &cib_object,
195 crm_trace("injecting node state for %s. rc is %d", node, rc);
196 }
197
198 free(xpath);
200 return cib_object;
201}
202
203static xmlNode *
204modify_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) {
213
214 } else {
219 }
220
222 return cib_node;
223}
224
225static xmlNode *
226find_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
238static xmlNode *
239inject_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 /* If an existing LRM history entry uses the resource name,
250 * continue using it, even if lrm_name is different.
251 */
252 return cib_resource;
253 }
254
255 // Check for history entry under preferred name
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 /* One day, add query for class, provider, type */
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
273 out->err(out, "Invalid class for %s: %s", resource, rclass);
274 return NULL;
275
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
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 // If we're creating a new entry, use the preferred name
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
313static int
314find_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,
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
355static int
356set_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
391void
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 /* crm_xml_add(top, XML_ATTR_DC_UUID, dc_uuid); */
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);
418 }
419
420 if (watchdog) {
422 XML_CIB_TAG_CRMCONFIG, NULL, NULL, NULL, NULL,
423 XML_ATTR_HAVE_WATCHDOG, watchdog, FALSE, NULL, NULL);
424
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,
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,
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,
459
460 snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", node,
462 cib->cmds->remove(cib, xpath, NULL,
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);
474 CRM_ASSERT(cib_node != NULL);
475
476 rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node,
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",
489
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",
500
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",
511
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",
522
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 {
563 rtype = crm_element_value(rsc->xml, XML_ATTR_TYPE);
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,
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
596static gboolean
597exec_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
609static gboolean
610exec_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
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 /* Look for the preferred name
645 * If not found, try the expected 'local' name
646 * If not found use the preferred name anyway
647 */
648 resource = crm_element_value(action_rsc, XML_ATTR_ID);
649 CRM_ASSERT(resource != NULL); // makes static analysis happy
650 lrm_name = resource; // Preferred name when writing history
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 // Allow user to specify anonymous clone with or without instance number
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 // ${match_name}_${task}_${interval_in_ms}@${node}=${rc}
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,
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
746static gboolean
747exec_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
759static gboolean
760exec_stonith_action(crm_graph_t * graph, crm_action_t * action)
761{
762 const char *op = crm_meta_value(action->params, "stonith_action");
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,
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,
782
783 snprintf(xpath, STATUS_PATH_MAX, "//node_state[@uname='%s']/%s", target,
785 fake_cib->cmds->remove(fake_cib, xpath, NULL,
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
797int
798run_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
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}
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard.
Definition agents.c:31
@ pcmk_ra_cap_provider
Definition agents.h:47
int query_node_uuid(cib_t *the_cib, const char *uname, char **uuid, int *is_remote_node)
Definition cib_attrs.c:484
int update_attr_delegate(cib_t *the_cib, int call_options, const char *section, const char *node_uuid, const char *set_type, const char *set_name, const char *attr_id, const char *attr_name, const char *attr_value, gboolean to_console, const char *user_name, const char *node_type)
Definition cib_attrs.c:169
Cluster Configuration.
@ cib_scope_local
Definition cib_types.h:59
@ cib_xpath
Definition cib_types.h:52
@ cib_sync_call
Definition cib_types.h:61
#define PCMK__OP_FMT
Definition internal.h:168
Utility functions.
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition operations.c:185
const char * crm_meta_value(GHashTable *hash, const char *field)
Definition utils.c:533
#define ONLINESTATUS
Definition util.h:38
#define OFFLINESTATUS
Definition util.h:39
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:114
A dumping ground.
#define RSC_METADATA
Definition crm.h:216
#define CRMD_JOINSTATE_DOWN
Definition crm.h:163
#define CRM_OP_REPROBE
Definition crm.h:154
#define CRM_FEATURE_SET
Definition crm.h:69
#define INFINITY
Definition crm.h:99
#define CRM_OP_PROBED
Definition crm.h:153
char * crm_system_name
Definition utils.c:54
#define CRMD_JOINSTATE_MEMBER
Definition crm.h:165
ISO_8601 Date handling.
#define crm_info(fmt, args...)
Definition logging.h:353
#define crm_log_xml_debug(xml, text)
Definition logging.h:363
#define CRM_LOG_ASSERT(expr)
Definition logging.h:202
#define crm_log_xml_err(xml, text)
Definition logging.h:359
#define crm_debug(fmt, args...)
Definition logging.h:355
#define crm_err(fmt, args...)
Definition logging.h:350
#define crm_log_xml_warn(xml, text)
Definition logging.h:360
#define crm_trace(fmt, args...)
Definition logging.h:356
#define LOG_TRACE
Definition logging.h:36
Resource agent executor.
void lrmd_free_event(lrmd_event_data_t *event)
Free an executor event.
lrmd_event_data_t * lrmd_new_event(const char *rsc_id, const char *task, guint interval_ms)
#define XML_TAG_CIB
Definition msg_xml.h:109
#define XML_BOOLEAN_NO
Definition msg_xml.h:143
#define XML_LRM_ATTR_ROUTER_NODE
Definition msg_xml.h:305
#define ID(x)
Definition msg_xml.h:456
#define XML_BOOLEAN_YES
Definition msg_xml.h:142
#define XML_ATTR_HAVE_WATCHDOG
Definition msg_xml.h:119
#define XML_ATTR_UNAME
Definition msg_xml.h:151
#define XML_CIB_TAG_TICKET_STATE
Definition msg_xml.h:427
#define XML_TAG_TRANSIENT_NODEATTRS
Definition msg_xml.h:403
#define XML_ATTR_UUID
Definition msg_xml.h:152
#define XML_NODE_IS_PEER
Definition msg_xml.h:278
#define XML_LRM_TAG_RESOURCES
Definition msg_xml.h:263
#define XML_LRM_ATTR_TASK_KEY
Definition msg_xml.h:298
#define XML_CIB_TAG_STATE
Definition msg_xml.h:198
#define XML_NODE_JOIN_STATE
Definition msg_xml.h:275
#define XML_CIB_TAG_CRMCONFIG
Definition msg_xml.h:184
#define XML_LRM_ATTR_TARGET_UUID
Definition msg_xml.h:300
#define XML_CIB_TAG_TICKETS
Definition msg_xml.h:426
#define XML_TAG_ATTR_SETS
Definition msg_xml.h:203
#define XML_ATTR_ID
Definition msg_xml.h:129
#define XML_NODE_IN_CLUSTER
Definition msg_xml.h:277
#define XML_ATTR_HAVE_QUORUM
Definition msg_xml.h:118
#define XML_AGENT_ATTR_PROVIDER
Definition msg_xml.h:267
#define XML_AGENT_ATTR_CLASS
Definition msg_xml.h:266
#define XML_ATTR_ID_LONG
Definition msg_xml.h:131
#define XML_ATTR_ORIGIN
Definition msg_xml.h:124
#define XML_LRM_ATTR_TASK
Definition msg_xml.h:297
#define XML_NODE_EXPECTED
Definition msg_xml.h:276
#define XML_ATTR_TYPE
Definition msg_xml.h:132
#define XML_LRM_ATTR_TARGET
Definition msg_xml.h:299
#define XML_CIB_TAG_NODES
Definition msg_xml.h:181
#define XML_CIB_TAG_STATUS
Definition msg_xml.h:179
#define XML_LRM_ATTR_CALLID
Definition msg_xml.h:309
#define XML_CIB_TAG_LRM
Definition msg_xml.h:262
#define XML_CIB_TAG_NODE
Definition msg_xml.h:199
#define XML_CIB_TAG_RESOURCE
Definition msg_xml.h:214
#define XML_ATTR_TE_TARGET_RC
Definition msg_xml.h:402
#define XML_LRM_TAG_RESOURCE
Definition msg_xml.h:264
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:530
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition nvpair.c:566
xmlNode * crm_create_nvpair_xml(xmlNode *parent, const char *id, const char *name, const char *value)
Create an XML name/value pair.
Definition nvpair.c:849
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition nvpair.c:727
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition nvpair.c:324
char * name
Definition pcmk_fence.c:31
const char * action
Definition pcmk_fence.c:30
int rc
Definition pcmk_fence.c:35
const char * target
Definition pcmk_fence.c:29
#define RSC_TEMPLATE
int run_simulation(pe_working_set_t *data_set, cib_t *cib, GList *op_fail_list)
#define STATUS_PATH_MAX
void modify_configuration(pe_working_set_t *data_set, cib_t *cib, const char *quorum, const char *watchdog, GList *node_up, GList *node_down, GList *node_fail, GList *op_inject, GList *ticket_grant, GList *ticket_revoke, GList *ticket_standby, GList *ticket_activate)
gboolean bringing_nodes_online
#define NODE_TEMPLATE
#define XPATH_MAX
#define NEW_NODE_TEMPLATE
xmlNode * pcmk__create_history_xml(xmlNode *parent, lrmd_event_data_t *event, const char *caller_version, int target_rc, const char *node, const char *origin, int level)
void set_graph_functions(crm_graph_functions_t *fns)
transition_status
@ transition_active
@ transition_complete
gboolean update_graph(crm_graph_t *graph, crm_action_t *action)
void print_graph(unsigned int log_level, crm_graph_t *graph)
lrmd_event_data_t * convert_graph_action(xmlNode *resource, crm_action_t *action, int status, int rc)
int run_graph(crm_graph_t *graph)
crm_graph_t * unpack_graph(xmlNode *xml_graph, const char *reference)
void destroy_graph(crm_graph_t *graph)
#define CRM_ASSERT(expr)
Definition results.h:42
@ CRM_EX_SOFTWARE
Definition results.h:235
_Noreturn crm_exit_t crm_exit(crm_exit_t rc)
Definition results.c:759
#define pcmk_ok
Definition results.h:67
#define PCMK_RESOURCE_CLASS_SYSTEMD
Definition services.h:46
#define PCMK_RESOURCE_CLASS_SERVICE
Definition services.h:44
#define PCMK_RESOURCE_CLASS_STONITH
Definition services.h:49
#define PCMK_RESOURCE_CLASS_OCF
Definition services.h:43
#define PCMK_RESOURCE_CLASS_UPSTART
Definition services.h:47
#define PCMK_RESOURCE_CLASS_LSB
Definition services.h:45
Cluster status and scheduling.
pe_resource_t * pe_find_resource(GList *rsc_list, const char *id_rh)
Definition status.c:382
void pe_reset_working_set(pe_working_set_t *data_set)
Reset a working set to default state without freeing it.
Definition status.c:329
int pcmk__scan_min_int(const char *text, int *result, int minimum)
Definition strings.c:127
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:955
@ pcmk__str_casei
int(* create)(cib_t *cib, const char *section, xmlNode *data, int call_options)
Definition cib_types.h:105
int(* remove)(cib_t *cib, const char *section, xmlNode *data, int call_options)
Definition cib_types.h:113
int(* query)(cib_t *cib, const char *section, xmlNode **output_data, int call_options)
Definition cib_types.h:92
int(* replace)(cib_t *cib, const char *section, xmlNode *data, int call_options)
Definition cib_types.h:111
int(* modify)(cib_t *cib, const char *section, xmlNode *data, int call_options)
Definition cib_types.h:107
cib_api_operations_t * cmds
Definition cib_types.h:147
const char * op_type
Definition lrmd.h:205
unsigned int t_run
Definition lrmd.h:227
unsigned int t_rcchange
Definition lrmd.h:229
enum ocf_exitcode rc
Definition lrmd.h:221
void * params
Definition lrmd.h:240
guint interval_ms
Definition lrmd.h:214
This structure contains everything that makes up a single output formatter.
void(* end_list)(pcmk__output_t *out)
int(* message)(pcmk__output_t *out, const char *message_id,...)
bool(* is_quiet)(pcmk__output_t *out)
int(*) void(* err)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
void(* begin_list)(pcmk__output_t *out, const char *singular_noun, const char *plural_noun, const char *format,...) G_GNUC_PRINTF(4
int(* info)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
xmlNode * xml
Definition pe_types.h:324
xmlNode * input
Definition pe_types.h:137
GList * resources
Definition pe_types.h:158
xmlNode * graph
Definition pe_types.h:176
gboolean xml_has_children(const xmlNode *root)
Definition xml.c:2027
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition xml.c:2790
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition xpath.c:214
void free_xml(xmlNode *child)
Definition xml.c:823
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition xml.c:696