This source file includes following definitions.
- inject_transient_attr
- pcmk__inject_failcount
- create_node_entry
- create_op
- pcmk__inject_action_result
- pcmk__inject_node
- pcmk__inject_node_state_change
- find_resource_xml
- pcmk__inject_resource_history
- find_ticket_state
- set_ticket_state_attr
- inject_action
- pcmk__inject_scheduler_input
- pcmk_free_injections
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/cib/internal.h>
25 #include <crm/common/util.h>
26 #include <crm/common/iso8601.h>
27 #include <crm/common/xml_internal.h>
28 #include <crm/lrmd_internal.h>
29 #include <crm/pengine/status.h>
30 #include <pacemaker-internal.h>
31
32 #include "libpacemaker_private.h"
33
34 bool pcmk__simulate_node_config = false;
35
36 #define XPATH_NODE_CONFIG "//" XML_CIB_TAG_NODE "[@uname='%s']"
37 #define XPATH_NODE_STATE "//" XML_CIB_TAG_STATE "[@uname='%s']"
38 #define XPATH_RSC_HISTORY XPATH_NODE_STATE "//" \
39 XML_LRM_TAG_RESOURCE "[@id='%s']"
40
41
42
43
44
45
46
47
48
49
50
51 static void
52 inject_transient_attr(pcmk__output_t *out, xmlNode *cib_node,
53 const char *name, const char *value)
54 {
55 xmlNode *attrs = NULL;
56 xmlNode *instance_attrs = NULL;
57 const char *node_uuid = ID(cib_node);
58
59 out->message(out, "inject-attr", name, value, cib_node);
60
61 attrs = first_named_child(cib_node, XML_TAG_TRANSIENT_NODEATTRS);
62 if (attrs == NULL) {
63 attrs = create_xml_node(cib_node, XML_TAG_TRANSIENT_NODEATTRS);
64 crm_xml_add(attrs, XML_ATTR_ID, node_uuid);
65 }
66
67 instance_attrs = first_named_child(attrs, XML_TAG_ATTR_SETS);
68 if (instance_attrs == NULL) {
69 instance_attrs = create_xml_node(attrs, XML_TAG_ATTR_SETS);
70 crm_xml_add(instance_attrs, XML_ATTR_ID, node_uuid);
71 }
72
73 crm_create_nvpair_xml(instance_attrs, NULL, name, value);
74 }
75
76
77
78
79
80
81
82
83
84
85
86
87
88 void
89 pcmk__inject_failcount(pcmk__output_t *out, xmlNode *cib_node,
90 const char *resource, const char *task,
91 guint interval_ms, int rc)
92 {
93 if (rc == 0) {
94 return;
95
96 } else if ((rc == 7) && (interval_ms == 0)) {
97 return;
98
99 } else {
100 char *name = NULL;
101 char *now = pcmk__ttoa(time(NULL));
102
103 name = pcmk__failcount_name(resource, task, interval_ms);
104 inject_transient_attr(out, cib_node, name, "value++");
105 free(name);
106
107 name = pcmk__lastfailure_name(resource, task, interval_ms);
108 inject_transient_attr(out, cib_node, name, now);
109 free(name);
110
111 free(now);
112 }
113 }
114
115
116
117
118
119
120
121
122 static void
123 create_node_entry(cib_t *cib_conn, const char *node)
124 {
125 int rc = pcmk_ok;
126 char *xpath = crm_strdup_printf(XPATH_NODE_CONFIG, node);
127
128 rc = cib_conn->cmds->query(cib_conn, xpath, NULL,
129 cib_xpath|cib_sync_call|cib_scope_local);
130
131 if (rc == -ENXIO) {
132 xmlNode *cib_object = create_xml_node(NULL, XML_CIB_TAG_NODE);
133
134 crm_xml_add(cib_object, XML_ATTR_ID, node);
135 crm_xml_add(cib_object, XML_ATTR_UNAME, node);
136 cib_conn->cmds->create(cib_conn, XML_CIB_TAG_NODES, cib_object,
137 cib_sync_call|cib_scope_local);
138
139
140
141 free_xml(cib_object);
142 }
143
144 free(xpath);
145 }
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160 static lrmd_event_data_t *
161 create_op(xmlNode *cib_resource, const char *task, guint interval_ms,
162 int outcome)
163 {
164 lrmd_event_data_t *op = NULL;
165 xmlNode *xop = NULL;
166
167 op = lrmd_new_event(ID(cib_resource), task, interval_ms);
168 lrmd__set_result(op, outcome, PCMK_EXEC_DONE, "Simulated action result");
169 op->params = NULL;
170 op->t_run = (unsigned int) time(NULL);
171 op->t_rcchange = op->t_run;
172
173
174 op->call_id = 0;
175 for (xop = pcmk__xe_first_child(cib_resource); xop != NULL;
176 xop = pcmk__xe_next(xop)) {
177
178 int tmp = 0;
179
180 crm_element_value_int(xop, XML_LRM_ATTR_CALLID, &tmp);
181 if (tmp > op->call_id) {
182 op->call_id = tmp;
183 }
184 }
185 op->call_id++;
186
187 return op;
188 }
189
190
191
192
193
194
195
196
197
198
199
200 xmlNode *
201 pcmk__inject_action_result(xmlNode *cib_resource, lrmd_event_data_t *op,
202 int target_rc)
203 {
204 return pcmk__create_history_xml(cib_resource, op, CRM_FEATURE_SET,
205 target_rc, NULL, crm_system_name);
206 }
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221 xmlNode *
222 pcmk__inject_node(cib_t *cib_conn, const char *node, const char *uuid)
223 {
224 int rc = pcmk_ok;
225 xmlNode *cib_object = NULL;
226 char *xpath = crm_strdup_printf(XPATH_NODE_STATE, node);
227
228 if (pcmk__simulate_node_config) {
229 create_node_entry(cib_conn, node);
230 }
231
232 rc = cib_conn->cmds->query(cib_conn, xpath, &cib_object,
233 cib_xpath|cib_sync_call|cib_scope_local);
234
235 if ((cib_object != NULL) && (ID(cib_object) == NULL)) {
236 crm_err("Detected multiple node_state entries for xpath=%s, bailing",
237 xpath);
238 crm_log_xml_warn(cib_object, "Duplicates");
239 free(xpath);
240 crm_exit(CRM_EX_SOFTWARE);
241 return NULL;
242 }
243
244 if (rc == -ENXIO) {
245 char *found_uuid = NULL;
246
247 if (uuid == NULL) {
248 query_node_uuid(cib_conn, node, &found_uuid, NULL);
249 } else {
250 found_uuid = strdup(uuid);
251 }
252
253 cib_object = create_xml_node(NULL, XML_CIB_TAG_STATE);
254 crm_xml_add(cib_object, XML_ATTR_UUID, found_uuid);
255 crm_xml_add(cib_object, XML_ATTR_UNAME, node);
256 cib_conn->cmds->create(cib_conn, XML_CIB_TAG_STATUS, cib_object,
257 cib_sync_call|cib_scope_local);
258 free_xml(cib_object);
259 free(found_uuid);
260
261 rc = cib_conn->cmds->query(cib_conn, xpath, &cib_object,
262 cib_xpath|cib_sync_call|cib_scope_local);
263 crm_trace("Injecting node state for %s (rc=%d)", node, rc);
264 }
265
266 free(xpath);
267 CRM_ASSERT(rc == pcmk_ok);
268 return cib_object;
269 }
270
271
272
273
274
275
276
277
278
279
280
281 xmlNode *
282 pcmk__inject_node_state_change(cib_t *cib_conn, const char *node, bool up)
283 {
284 xmlNode *cib_node = pcmk__inject_node(cib_conn, node, NULL);
285
286 if (up) {
287 pcmk__xe_set_props(cib_node,
288 XML_NODE_IN_CLUSTER, XML_BOOLEAN_YES,
289 XML_NODE_IS_PEER, ONLINESTATUS,
290 XML_NODE_JOIN_STATE, CRMD_JOINSTATE_MEMBER,
291 XML_NODE_EXPECTED, CRMD_JOINSTATE_MEMBER,
292 NULL);
293 } else {
294 pcmk__xe_set_props(cib_node,
295 XML_NODE_IN_CLUSTER, XML_BOOLEAN_NO,
296 XML_NODE_IS_PEER, OFFLINESTATUS,
297 XML_NODE_JOIN_STATE, CRMD_JOINSTATE_DOWN,
298 XML_NODE_EXPECTED, CRMD_JOINSTATE_DOWN,
299 NULL);
300 }
301 crm_xml_add(cib_node, XML_ATTR_ORIGIN, crm_system_name);
302 return cib_node;
303 }
304
305
306
307
308
309
310
311
312
313
314
315 static xmlNode *
316 find_resource_xml(xmlNode *cib_node, const char *resource)
317 {
318 const char *node = crm_element_value(cib_node, XML_ATTR_UNAME);
319 char *xpath = crm_strdup_printf(XPATH_RSC_HISTORY, node, resource);
320 xmlNode *match = get_xpath_object(xpath, cib_node, LOG_TRACE);
321
322 free(xpath);
323 return match;
324 }
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342 xmlNode *
343 pcmk__inject_resource_history(pcmk__output_t *out, xmlNode *cib_node,
344 const char *resource, const char *lrm_name,
345 const char *rclass, const char *rtype,
346 const char *rprovider)
347 {
348 xmlNode *lrm = NULL;
349 xmlNode *container = NULL;
350 xmlNode *cib_resource = NULL;
351
352 cib_resource = find_resource_xml(cib_node, resource);
353 if (cib_resource != NULL) {
354
355
356
357 return cib_resource;
358 }
359
360
361 if (strcmp(resource, lrm_name) != 0) {
362 cib_resource = find_resource_xml(cib_node, lrm_name);
363 if (cib_resource != NULL) {
364 return cib_resource;
365 }
366 }
367
368 if ((rclass == NULL) || (rtype == NULL)) {
369
370 out->err(out, "Resource %s not found in the status section of %s."
371 " Please supply the class and type to continue", resource, ID(cib_node));
372 return NULL;
373
374 } else if (!pcmk__strcase_any_of(rclass,
375 PCMK_RESOURCE_CLASS_OCF,
376 PCMK_RESOURCE_CLASS_STONITH,
377 PCMK_RESOURCE_CLASS_SERVICE,
378 PCMK_RESOURCE_CLASS_UPSTART,
379 PCMK_RESOURCE_CLASS_SYSTEMD,
380 PCMK_RESOURCE_CLASS_LSB, NULL)) {
381 out->err(out, "Invalid class for %s: %s", resource, rclass);
382 return NULL;
383
384 } else if (pcmk_is_set(pcmk_get_ra_caps(rclass), pcmk_ra_cap_provider)
385 && (rprovider == NULL)) {
386
387 out->err(out, "Please specify the provider for resource %s", resource);
388 return NULL;
389 }
390
391 crm_info("Injecting new resource %s into node state '%s'",
392 lrm_name, ID(cib_node));
393
394 lrm = first_named_child(cib_node, XML_CIB_TAG_LRM);
395 if (lrm == NULL) {
396 const char *node_uuid = ID(cib_node);
397
398 lrm = create_xml_node(cib_node, XML_CIB_TAG_LRM);
399 crm_xml_add(lrm, XML_ATTR_ID, node_uuid);
400 }
401
402 container = first_named_child(lrm, XML_LRM_TAG_RESOURCES);
403 if (container == NULL) {
404 container = create_xml_node(lrm, XML_LRM_TAG_RESOURCES);
405 }
406
407 cib_resource = create_xml_node(container, XML_LRM_TAG_RESOURCE);
408
409
410 crm_xml_add(cib_resource, XML_ATTR_ID, lrm_name);
411
412 crm_xml_add(cib_resource, XML_AGENT_ATTR_CLASS, rclass);
413 crm_xml_add(cib_resource, XML_AGENT_ATTR_PROVIDER, rprovider);
414 crm_xml_add(cib_resource, XML_ATTR_TYPE, rtype);
415
416 return cib_resource;
417 }
418
419 #define XPATH_MAX 1024
420
421 static int
422 find_ticket_state(pcmk__output_t *out, cib_t *the_cib, const char *ticket_id,
423 xmlNode **ticket_state_xml)
424 {
425 int offset = 0;
426 int rc = pcmk_ok;
427 xmlNode *xml_search = NULL;
428
429 char *xpath_string = NULL;
430
431 CRM_ASSERT(ticket_state_xml != NULL);
432 *ticket_state_xml = NULL;
433
434 xpath_string = calloc(1, XPATH_MAX);
435 offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "%s", "/cib/status/tickets");
436
437 if (ticket_id) {
438 offset += snprintf(xpath_string + offset, XPATH_MAX - offset, "/%s[@id=\"%s\"]",
439 XML_CIB_TAG_TICKET_STATE, ticket_id);
440 }
441 CRM_LOG_ASSERT(offset > 0);
442 rc = the_cib->cmds->query(the_cib, xpath_string, &xml_search,
443 cib_sync_call|cib_scope_local|cib_xpath);
444
445 if (rc != pcmk_ok) {
446 goto bail;
447 }
448
449 crm_log_xml_debug(xml_search, "Match");
450 if (xml_has_children(xml_search)) {
451 if (ticket_id) {
452 out->err(out, "Multiple ticket_states match ticket_id=%s", ticket_id);
453 }
454 *ticket_state_xml = xml_search;
455 } else {
456 *ticket_state_xml = xml_search;
457 }
458
459 bail:
460 free(xpath_string);
461 return rc;
462 }
463
464
465
466
467
468
469
470
471
472
473
474
475
476 static int
477 set_ticket_state_attr(pcmk__output_t *out, const char *ticket_id,
478 const char *attr_name, bool attr_value, cib_t *cib)
479 {
480 int rc = pcmk_rc_ok;
481 xmlNode *xml_top = NULL;
482 xmlNode *ticket_state_xml = NULL;
483
484
485 rc = find_ticket_state(out, cib, ticket_id, &ticket_state_xml);
486 rc = pcmk_legacy2rc(rc);
487
488 if (rc == pcmk_rc_ok) {
489 crm_debug("Injecting attribute into existing ticket state %s",
490 ticket_id);
491 xml_top = ticket_state_xml;
492
493 } else if (rc == ENXIO) {
494 xmlNode *xml_obj = NULL;
495
496 xml_top = create_xml_node(NULL, XML_CIB_TAG_STATUS);
497 xml_obj = create_xml_node(xml_top, XML_CIB_TAG_TICKETS);
498 ticket_state_xml = create_xml_node(xml_obj, XML_CIB_TAG_TICKET_STATE);
499 crm_xml_add(ticket_state_xml, XML_ATTR_ID, ticket_id);
500
501 } else {
502 return rc;
503 }
504
505
506 pcmk__xe_set_bool_attr(ticket_state_xml, attr_name, attr_value);
507 crm_log_xml_debug(xml_top, "Update");
508
509
510 rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, xml_top,
511 cib_sync_call|cib_scope_local);
512 rc = pcmk_legacy2rc(rc);
513
514 free_xml(xml_top);
515 return rc;
516 }
517
518
519
520
521
522
523
524
525
526
527 static void
528 inject_action(pcmk__output_t *out, const char *spec, cib_t *cib,
529 pe_working_set_t *data_set)
530 {
531 int rc;
532 int outcome = PCMK_OCF_OK;
533 guint interval_ms = 0;
534
535 char *key = NULL;
536 char *node = NULL;
537 char *task = NULL;
538 char *resource = NULL;
539
540 const char *rtype = NULL;
541 const char *rclass = NULL;
542 const char *rprovider = NULL;
543
544 xmlNode *cib_op = NULL;
545 xmlNode *cib_node = NULL;
546 xmlNode *cib_resource = NULL;
547 pe_resource_t *rsc = NULL;
548 lrmd_event_data_t *op = NULL;
549
550 out->message(out, "inject-spec", spec);
551
552 key = calloc(1, strlen(spec) + 1);
553 node = calloc(1, strlen(spec) + 1);
554 rc = sscanf(spec, "%[^@]@%[^=]=%d", key, node, &outcome);
555 if (rc != 3) {
556 out->err(out, "Invalid operation spec: %s. Only found %d fields",
557 spec, rc);
558 goto done;
559 }
560
561 parse_op_key(key, &resource, &task, &interval_ms);
562
563 rsc = pe_find_resource(data_set->resources, resource);
564 if (rsc == NULL) {
565 out->err(out, "Invalid resource name: %s", resource);
566 goto done;
567 }
568
569 rclass = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
570 rtype = crm_element_value(rsc->xml, XML_ATTR_TYPE);
571 rprovider = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
572
573 cib_node = pcmk__inject_node(cib, node, NULL);
574 CRM_ASSERT(cib_node != NULL);
575
576 pcmk__inject_failcount(out, cib_node, resource, task, interval_ms, outcome);
577
578 cib_resource = pcmk__inject_resource_history(out, cib_node,
579 resource, resource,
580 rclass, rtype, rprovider);
581 CRM_ASSERT(cib_resource != NULL);
582
583 op = create_op(cib_resource, task, interval_ms, outcome);
584 CRM_ASSERT(op != NULL);
585
586 cib_op = pcmk__inject_action_result(cib_resource, op, 0);
587 CRM_ASSERT(cib_op != NULL);
588 lrmd_free_event(op);
589
590 rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node,
591 cib_sync_call|cib_scope_local);
592 CRM_ASSERT(rc == pcmk_ok);
593
594 done:
595 free(task);
596 free(node);
597 free(key);
598 }
599
600
601
602
603
604
605
606
607
608 void
609 pcmk__inject_scheduler_input(pe_working_set_t *data_set, cib_t *cib,
610 pcmk_injections_t *injections)
611 {
612 int rc = pcmk_ok;
613 GList *iter = NULL;
614 xmlNode *cib_node = NULL;
615 pcmk__output_t *out = data_set->priv;
616
617 out->message(out, "inject-modify-config", injections->quorum,
618 injections->watchdog);
619 if (injections->quorum != NULL) {
620 xmlNode *top = create_xml_node(NULL, XML_TAG_CIB);
621
622
623 crm_xml_add(top, XML_ATTR_HAVE_QUORUM, injections->quorum);
624
625 rc = cib->cmds->modify(cib, NULL, top, cib_sync_call|cib_scope_local);
626 CRM_ASSERT(rc == pcmk_ok);
627 }
628
629 if (injections->watchdog != NULL) {
630 rc = cib__update_node_attr(out, cib, cib_sync_call|cib_scope_local,
631 XML_CIB_TAG_CRMCONFIG, NULL, NULL, NULL, NULL,
632 XML_ATTR_HAVE_WATCHDOG, injections->watchdog,
633 NULL, NULL);
634 CRM_ASSERT(rc == pcmk_rc_ok);
635 }
636
637 for (iter = injections->node_up; iter != NULL; iter = iter->next) {
638 char *node = (char *) iter->data;
639
640 out->message(out, "inject-modify-node", "Online", node);
641
642 cib_node = pcmk__inject_node_state_change(cib, node, true);
643 CRM_ASSERT(cib_node != NULL);
644
645 rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node,
646 cib_sync_call|cib_scope_local);
647 CRM_ASSERT(rc == pcmk_ok);
648 free_xml(cib_node);
649 }
650
651 for (iter = injections->node_down; iter != NULL; iter = iter->next) {
652 char *node = (char *) iter->data;
653 char *xpath = NULL;
654
655 out->message(out, "inject-modify-node", "Offline", node);
656
657 cib_node = pcmk__inject_node_state_change(cib, node, false);
658 CRM_ASSERT(cib_node != NULL);
659
660 rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node,
661 cib_sync_call|cib_scope_local);
662 CRM_ASSERT(rc == pcmk_ok);
663 free_xml(cib_node);
664
665 xpath = crm_strdup_printf("//node_state[@uname='%s']/%s",
666 node, XML_CIB_TAG_LRM);
667 cib->cmds->remove(cib, xpath, NULL,
668 cib_xpath|cib_sync_call|cib_scope_local);
669 free(xpath);
670
671 xpath = crm_strdup_printf("//node_state[@uname='%s']/%s",
672 node, XML_TAG_TRANSIENT_NODEATTRS);
673 cib->cmds->remove(cib, xpath, NULL,
674 cib_xpath|cib_sync_call|cib_scope_local);
675 free(xpath);
676 }
677
678 for (iter = injections->node_fail; iter != NULL; iter = iter->next) {
679 char *node = (char *) iter->data;
680
681 out->message(out, "inject-modify-node", "Failing", node);
682
683 cib_node = pcmk__inject_node_state_change(cib, node, true);
684 crm_xml_add(cib_node, XML_NODE_IN_CLUSTER, XML_BOOLEAN_NO);
685 CRM_ASSERT(cib_node != NULL);
686
687 rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, cib_node,
688 cib_sync_call|cib_scope_local);
689 CRM_ASSERT(rc == pcmk_ok);
690 free_xml(cib_node);
691 }
692
693 for (iter = injections->ticket_grant; iter != NULL; iter = iter->next) {
694 char *ticket_id = (char *) iter->data;
695
696 out->message(out, "inject-modify-ticket", "Granting", ticket_id);
697
698 rc = set_ticket_state_attr(out, ticket_id, "granted", true, cib);
699 CRM_ASSERT(rc == pcmk_rc_ok);
700 }
701
702 for (iter = injections->ticket_revoke; iter != NULL; iter = iter->next) {
703 char *ticket_id = (char *) iter->data;
704
705 out->message(out, "inject-modify-ticket", "Revoking", ticket_id);
706
707 rc = set_ticket_state_attr(out, ticket_id, "granted", false, cib);
708 CRM_ASSERT(rc == pcmk_rc_ok);
709 }
710
711 for (iter = injections->ticket_standby; iter != NULL; iter = iter->next) {
712 char *ticket_id = (char *) iter->data;
713
714 out->message(out, "inject-modify-ticket", "Standby", ticket_id);
715
716 rc = set_ticket_state_attr(out, ticket_id, "standby", true, cib);
717 CRM_ASSERT(rc == pcmk_rc_ok);
718 }
719
720 for (iter = injections->ticket_activate; iter != NULL; iter = iter->next) {
721 char *ticket_id = (char *) iter->data;
722
723 out->message(out, "inject-modify-ticket", "Activating", ticket_id);
724
725 rc = set_ticket_state_attr(out, ticket_id, "standby", false, cib);
726 CRM_ASSERT(rc == pcmk_rc_ok);
727 }
728
729 for (iter = injections->op_inject; iter != NULL; iter = iter->next) {
730 inject_action(out, (char *) iter->data, cib, data_set);
731 }
732
733 if (!out->is_quiet(out)) {
734 out->end_list(out);
735 }
736 }
737
738 void
739 pcmk_free_injections(pcmk_injections_t *injections)
740 {
741 if (injections == NULL) {
742 return;
743 }
744
745 g_list_free_full(injections->node_up, g_free);
746 g_list_free_full(injections->node_down, g_free);
747 g_list_free_full(injections->node_fail, g_free);
748 g_list_free_full(injections->op_fail, g_free);
749 g_list_free_full(injections->op_inject, g_free);
750 g_list_free_full(injections->ticket_grant, g_free);
751 g_list_free_full(injections->ticket_revoke, g_free);
752 g_list_free_full(injections->ticket_standby, g_free);
753 g_list_free_full(injections->ticket_activate, g_free);
754 free(injections->quorum);
755 free(injections->watchdog);
756
757 free(injections);
758 }