This source file includes following definitions.
- node_has_attr
- add_topology_level
- topology_remove_helper
- remove_topology_level
- register_fencing_topology
- fencing_topology_init
- remove_cib_device
- update_stonith_watchdog_timeout_ms
- cib_devices_update
- update_cib_stonith_devices_v1
- update_cib_stonith_devices_v2
- update_cib_stonith_devices
- watchdog_device_update
- fenced_query_cib
- remove_fencing_topology
- update_fencing_topology
- update_cib_cache_cb
- init_cib_cache_cb
- cib_connection_destroy
- fenced_cib_cleanup
- setup_cib
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <stdbool.h>
13 #include <stdio.h>
14 #include <libxml/tree.h>
15 #include <libxml/xpath.h>
16
17 #include <crm/crm.h>
18 #include <crm/msg_xml.h>
19 #include <crm/common/xml.h>
20
21 #include <crm/cluster/internal.h>
22
23 #include <crm/cib.h>
24 #include <crm/cib/internal.h>
25
26 #include <pacemaker-fenced.h>
27
28 static xmlNode *local_cib = NULL;
29 static cib_t *cib_api = NULL;
30 static bool have_cib_devices = FALSE;
31
32
33
34
35
36
37
38
39
40
41
42 gboolean
43 node_has_attr(const char *node, const char *name, const char *value)
44 {
45 GString *xpath = NULL;
46 xmlNode *match;
47
48 CRM_CHECK((local_cib != NULL) && (node != NULL) && (name != NULL)
49 && (value != NULL), return FALSE);
50
51
52
53
54
55
56 xpath = g_string_sized_new(256);
57 pcmk__g_strcat(xpath,
58 "//" XML_CIB_TAG_NODES "/" XML_CIB_TAG_NODE
59 "[@" XML_ATTR_UNAME "='", node, "']/" XML_TAG_ATTR_SETS
60 "/" XML_CIB_TAG_NVPAIR
61 "[@" XML_NVPAIR_ATTR_NAME "='", name, "' "
62 "and @" XML_NVPAIR_ATTR_VALUE "='", value, "']", NULL);
63
64 match = get_xpath_object((const char *) xpath->str, local_cib, LOG_NEVER);
65
66 g_string_free(xpath, TRUE);
67 return (match != NULL);
68 }
69
70 static void
71 add_topology_level(xmlNode *match)
72 {
73 char *desc = NULL;
74 pcmk__action_result_t result = PCMK__UNKNOWN_RESULT;
75
76 CRM_CHECK(match != NULL, return);
77
78 fenced_register_level(match, &desc, &result);
79 fenced_send_level_notification(STONITH_OP_LEVEL_ADD, &result, desc);
80 pcmk__reset_result(&result);
81 free(desc);
82 }
83
84 static void
85 topology_remove_helper(const char *node, int level)
86 {
87 char *desc = NULL;
88 pcmk__action_result_t result = PCMK__UNKNOWN_RESULT;
89 xmlNode *data = create_xml_node(NULL, XML_TAG_FENCING_LEVEL);
90
91 crm_xml_add(data, F_STONITH_ORIGIN, __func__);
92 crm_xml_add_int(data, XML_ATTR_STONITH_INDEX, level);
93 crm_xml_add(data, XML_ATTR_STONITH_TARGET, node);
94
95 fenced_unregister_level(data, &desc, &result);
96 fenced_send_level_notification(STONITH_OP_LEVEL_DEL, &result, desc);
97 pcmk__reset_result(&result);
98 free_xml(data);
99 free(desc);
100 }
101
102 static void
103 remove_topology_level(xmlNode *match)
104 {
105 int index = 0;
106 char *key = NULL;
107
108 CRM_CHECK(match != NULL, return);
109
110 key = stonith_level_key(match, fenced_target_by_unknown);
111 crm_element_value_int(match, XML_ATTR_STONITH_INDEX, &index);
112 topology_remove_helper(key, index);
113 free(key);
114 }
115
116 static void
117 register_fencing_topology(xmlXPathObjectPtr xpathObj)
118 {
119 int max = numXpathResults(xpathObj), lpc = 0;
120
121 for (lpc = 0; lpc < max; lpc++) {
122 xmlNode *match = getXpathResult(xpathObj, lpc);
123
124 remove_topology_level(match);
125 add_topology_level(match);
126 }
127 }
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148 void
149 fencing_topology_init(void)
150 {
151 xmlXPathObjectPtr xpathObj = NULL;
152 const char *xpath = "//" XML_TAG_FENCING_LEVEL;
153
154 crm_trace("Full topology refresh");
155 free_topology_list();
156 init_topology_list();
157
158
159 xpathObj = xpath_search(local_cib, xpath);
160 register_fencing_topology(xpathObj);
161
162 freeXpathObject(xpathObj);
163 }
164
165 static void
166 remove_cib_device(xmlXPathObjectPtr xpathObj)
167 {
168 int max = numXpathResults(xpathObj), lpc = 0;
169
170 for (lpc = 0; lpc < max; lpc++) {
171 const char *rsc_id = NULL;
172 const char *standard = NULL;
173 xmlNode *match = getXpathResult(xpathObj, lpc);
174
175 CRM_LOG_ASSERT(match != NULL);
176 if(match != NULL) {
177 standard = crm_element_value(match, XML_AGENT_ATTR_CLASS);
178 }
179
180 if (!pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
181 continue;
182 }
183
184 rsc_id = crm_element_value(match, XML_ATTR_ID);
185
186 stonith_device_remove(rsc_id, true);
187 }
188 }
189
190 static void
191 update_stonith_watchdog_timeout_ms(xmlNode *cib)
192 {
193 long timeout_ms = 0;
194 xmlNode *stonith_watchdog_xml = NULL;
195 const char *value = NULL;
196
197 stonith_watchdog_xml = get_xpath_object("//nvpair[@name='stonith-watchdog-timeout']",
198 cib, LOG_NEVER);
199 if (stonith_watchdog_xml) {
200 value = crm_element_value(stonith_watchdog_xml, XML_NVPAIR_ATTR_VALUE);
201 }
202 if (value) {
203 timeout_ms = crm_get_msec(value);
204 }
205
206 if (timeout_ms < 0) {
207 timeout_ms = pcmk__auto_watchdog_timeout();
208 }
209
210 stonith_watchdog_timeout_ms = timeout_ms;
211 }
212
213
214
215
216
217 static void
218 cib_devices_update(void)
219 {
220 GHashTableIter iter;
221 stonith_device_t *device = NULL;
222
223 crm_info("Updating devices to version %s.%s.%s",
224 crm_element_value(local_cib, XML_ATTR_GENERATION_ADMIN),
225 crm_element_value(local_cib, XML_ATTR_GENERATION),
226 crm_element_value(local_cib, XML_ATTR_NUMUPDATES));
227
228 g_hash_table_iter_init(&iter, device_list);
229 while (g_hash_table_iter_next(&iter, NULL, (void **)&device)) {
230 if (device->cib_registered) {
231 device->dirty = TRUE;
232 }
233 }
234
235
236
237
238 g_list_free_full(stonith_watchdog_targets, free);
239 stonith_watchdog_targets = NULL;
240
241 fenced_scheduler_run(local_cib);
242
243 g_hash_table_iter_init(&iter, device_list);
244 while (g_hash_table_iter_next(&iter, NULL, (void **)&device)) {
245 if (device->dirty) {
246 g_hash_table_iter_remove(&iter);
247 }
248 }
249 }
250
251 static void
252 update_cib_stonith_devices_v1(const char *event, xmlNode * msg)
253 {
254 const char *reason = "none";
255 gboolean needs_update = FALSE;
256 xmlXPathObjectPtr xpath_obj = NULL;
257
258
259 xpath_obj = xpath_search(msg, "//" F_CIB_UPDATE_RESULT "//" XML_CONS_TAG_RSC_LOCATION);
260 if (numXpathResults(xpath_obj) > 0) {
261 int max = numXpathResults(xpath_obj), lpc = 0;
262
263
264 needs_update = TRUE;
265 reason = "new location constraint";
266
267 for (lpc = 0; lpc < max; lpc++) {
268 xmlNode *match = getXpathResult(xpath_obj, lpc);
269
270 crm_log_xml_trace(match, "new constraint");
271 }
272 }
273 freeXpathObject(xpath_obj);
274
275
276 xpath_obj = xpath_search(msg, "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_REMOVED "//" XML_CIB_TAG_RESOURCE);
277 if (numXpathResults(xpath_obj) > 0) {
278 remove_cib_device(xpath_obj);
279 }
280 freeXpathObject(xpath_obj);
281
282
283 xpath_obj = xpath_search(msg, "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//" XML_CIB_TAG_RESOURCE);
284 if (numXpathResults(xpath_obj) > 0) {
285 int max = numXpathResults(xpath_obj), lpc = 0;
286
287 for (lpc = 0; lpc < max; lpc++) {
288 const char *rsc_id = NULL;
289 const char *standard = NULL;
290 xmlNode *match = getXpathResult(xpath_obj, lpc);
291
292 rsc_id = crm_element_value(match, XML_ATTR_ID);
293 standard = crm_element_value(match, XML_AGENT_ATTR_CLASS);
294
295 if (!pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
296 continue;
297 }
298
299 crm_trace("Fencing resource %s was added or modified", rsc_id);
300 reason = "new resource";
301 needs_update = TRUE;
302 }
303 }
304 freeXpathObject(xpath_obj);
305
306 if(needs_update) {
307 crm_info("Updating device list from CIB: %s", reason);
308 cib_devices_update();
309 }
310 }
311
312 static void
313 update_cib_stonith_devices_v2(const char *event, xmlNode * msg)
314 {
315 xmlNode *change = NULL;
316 char *reason = NULL;
317 bool needs_update = FALSE;
318 xmlNode *patchset = get_message_xml(msg, F_CIB_UPDATE_RESULT);
319
320 for (change = pcmk__xml_first_child(patchset); change != NULL;
321 change = pcmk__xml_next(change)) {
322 const char *op = crm_element_value(change, XML_DIFF_OP);
323 const char *xpath = crm_element_value(change, XML_DIFF_PATH);
324 const char *shortpath = NULL;
325
326 if ((op == NULL) ||
327 (strcmp(op, "move") == 0) ||
328 strstr(xpath, "/"XML_CIB_TAG_STATUS)) {
329 continue;
330 } else if (pcmk__str_eq(op, "delete", pcmk__str_casei) && strstr(xpath, "/"XML_CIB_TAG_RESOURCE)) {
331 const char *rsc_id = NULL;
332 char *search = NULL;
333 char *mutable = NULL;
334
335 if (strstr(xpath, XML_TAG_ATTR_SETS) ||
336 strstr(xpath, XML_TAG_META_SETS)) {
337 needs_update = TRUE;
338 pcmk__str_update(&reason,
339 "(meta) attribute deleted from resource");
340 break;
341 }
342 pcmk__str_update(&mutable, xpath);
343 rsc_id = strstr(mutable, "primitive[@" XML_ATTR_ID "=\'");
344 if (rsc_id != NULL) {
345 rsc_id += strlen("primitive[@" XML_ATTR_ID "=\'");
346 search = strchr(rsc_id, '\'');
347 }
348 if (search != NULL) {
349 *search = 0;
350 stonith_device_remove(rsc_id, true);
351
352
353 } else {
354 crm_warn("Ignoring malformed CIB update (resource deletion)");
355 }
356 free(mutable);
357
358 } else if (strstr(xpath, "/"XML_CIB_TAG_RESOURCES) ||
359 strstr(xpath, "/"XML_CIB_TAG_CONSTRAINTS) ||
360 strstr(xpath, "/"XML_CIB_TAG_RSCCONFIG)) {
361 shortpath = strrchr(xpath, '/'); CRM_ASSERT(shortpath);
362 reason = crm_strdup_printf("%s %s", op, shortpath+1);
363 needs_update = TRUE;
364 break;
365 }
366 }
367
368 if(needs_update) {
369 crm_info("Updating device list from CIB: %s", reason);
370 cib_devices_update();
371 } else {
372 crm_trace("No updates for device list found in CIB");
373 }
374 free(reason);
375 }
376
377 static void
378 update_cib_stonith_devices(const char *event, xmlNode * msg)
379 {
380 int format = 1;
381 xmlNode *patchset = get_message_xml(msg, F_CIB_UPDATE_RESULT);
382
383 CRM_ASSERT(patchset);
384 crm_element_value_int(patchset, PCMK_XA_FORMAT, &format);
385 switch(format) {
386 case 1:
387 update_cib_stonith_devices_v1(event, msg);
388 break;
389 case 2:
390 update_cib_stonith_devices_v2(event, msg);
391 break;
392 default:
393 crm_warn("Unknown patch format: %d", format);
394 }
395 }
396
397 static void
398 watchdog_device_update(void)
399 {
400 if (stonith_watchdog_timeout_ms > 0) {
401 if (!g_hash_table_lookup(device_list, STONITH_WATCHDOG_ID) &&
402 !stonith_watchdog_targets) {
403
404
405
406 int rc;
407 xmlNode *xml;
408
409 xml = create_device_registration_xml(
410 STONITH_WATCHDOG_ID,
411 st_namespace_internal,
412 STONITH_WATCHDOG_AGENT,
413 NULL,
414
415
416
417 NULL);
418 rc = stonith_device_register(xml, TRUE);
419 free_xml(xml);
420 if (rc != pcmk_ok) {
421 rc = pcmk_legacy2rc(rc);
422 exit_code = CRM_EX_FATAL;
423 crm_crit("Cannot register watchdog pseudo fence agent: %s",
424 pcmk_rc_str(rc));
425 stonith_shutdown(0);
426 }
427 }
428
429 } else if (g_hash_table_lookup(device_list, STONITH_WATCHDOG_ID) != NULL) {
430
431 stonith_device_remove(STONITH_WATCHDOG_ID, true);
432 }
433 }
434
435
436
437
438
439
440
441 static int
442 fenced_query_cib(void)
443 {
444 int rc = pcmk_ok;
445
446 crm_trace("Re-requesting full CIB");
447 rc = cib_api->cmds->query(cib_api, NULL, &local_cib,
448 cib_scope_local|cib_sync_call);
449 rc = pcmk_legacy2rc(rc);
450 if (rc == pcmk_rc_ok) {
451 CRM_ASSERT(local_cib != NULL);
452 } else {
453 crm_err("Couldn't retrieve the CIB: %s " CRM_XS " rc=%d",
454 pcmk_rc_str(rc), rc);
455 }
456 return rc;
457 }
458
459 static void
460 remove_fencing_topology(xmlXPathObjectPtr xpathObj)
461 {
462 int max = numXpathResults(xpathObj), lpc = 0;
463
464 for (lpc = 0; lpc < max; lpc++) {
465 xmlNode *match = getXpathResult(xpathObj, lpc);
466
467 CRM_LOG_ASSERT(match != NULL);
468 if (match && crm_element_value(match, XML_DIFF_MARKER)) {
469
470 int index = 0;
471 char *target = stonith_level_key(match, fenced_target_by_unknown);
472
473 crm_element_value_int(match, XML_ATTR_STONITH_INDEX, &index);
474 if (target == NULL) {
475 crm_err("Invalid fencing target in element %s", ID(match));
476
477 } else if (index <= 0) {
478 crm_err("Invalid level for %s in element %s", target, ID(match));
479
480 } else {
481 topology_remove_helper(target, index);
482 }
483
484 }
485 }
486 }
487
488 static void
489 update_fencing_topology(const char *event, xmlNode * msg)
490 {
491 int format = 1;
492 const char *xpath;
493 xmlXPathObjectPtr xpathObj = NULL;
494 xmlNode *patchset = get_message_xml(msg, F_CIB_UPDATE_RESULT);
495
496 CRM_ASSERT(patchset);
497 crm_element_value_int(patchset, PCMK_XA_FORMAT, &format);
498
499 if(format == 1) {
500
501 xpath = "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_REMOVED "//" XML_TAG_FENCING_LEVEL;
502 xpathObj = xpath_search(msg, xpath);
503
504 remove_fencing_topology(xpathObj);
505 freeXpathObject(xpathObj);
506
507
508 xpath = "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//" XML_TAG_FENCING_LEVEL;
509 xpathObj = xpath_search(msg, xpath);
510
511 register_fencing_topology(xpathObj);
512 freeXpathObject(xpathObj);
513
514 } else if(format == 2) {
515 xmlNode *change = NULL;
516 int add[] = { 0, 0, 0 };
517 int del[] = { 0, 0, 0 };
518
519 xml_patch_versions(patchset, add, del);
520
521 for (change = pcmk__xml_first_child(patchset); change != NULL;
522 change = pcmk__xml_next(change)) {
523 const char *op = crm_element_value(change, XML_DIFF_OP);
524 const char *xpath = crm_element_value(change, XML_DIFF_PATH);
525
526 if(op == NULL) {
527 continue;
528
529 } else if(strstr(xpath, "/" XML_TAG_FENCING_LEVEL) != NULL) {
530
531
532 crm_trace("Handling %s operation %d.%d.%d for %s", op, add[0], add[1], add[2], xpath);
533 if(strcmp(op, "move") == 0) {
534 continue;
535
536 } else if(strcmp(op, "create") == 0) {
537 add_topology_level(change->children);
538
539 } else if(strcmp(op, "modify") == 0) {
540 xmlNode *match = first_named_child(change, XML_DIFF_RESULT);
541
542 if(match) {
543 remove_topology_level(match->children);
544 add_topology_level(match->children);
545 }
546
547 } else if(strcmp(op, "delete") == 0) {
548
549 crm_info("Re-initializing fencing topology after %s operation %d.%d.%d for %s",
550 op, add[0], add[1], add[2], xpath);
551 fencing_topology_init();
552 return;
553 }
554
555 } else if (strstr(xpath, "/" XML_TAG_FENCING_TOPOLOGY) != NULL) {
556
557 crm_info("Re-initializing fencing topology after top-level %s operation %d.%d.%d for %s",
558 op, add[0], add[1], add[2], xpath);
559 fencing_topology_init();
560 return;
561
562 } else if (strstr(xpath, "/" XML_CIB_TAG_CONFIGURATION)) {
563
564 if(first_named_child(change, XML_TAG_FENCING_TOPOLOGY) == NULL) {
565 crm_trace("Nothing for us in %s operation %d.%d.%d for %s.",
566 op, add[0], add[1], add[2], xpath);
567
568 } else if(strcmp(op, "delete") == 0 || strcmp(op, "create") == 0) {
569 crm_info("Re-initializing fencing topology after top-level %s operation %d.%d.%d for %s.",
570 op, add[0], add[1], add[2], xpath);
571 fencing_topology_init();
572 return;
573 }
574
575 } else {
576 crm_trace("Nothing for us in %s operation %d.%d.%d for %s",
577 op, add[0], add[1], add[2], xpath);
578 }
579 }
580
581 } else {
582 crm_warn("Unknown patch format: %d", format);
583 }
584 }
585
586 static void
587 update_cib_cache_cb(const char *event, xmlNode * msg)
588 {
589 long timeout_ms_saved = stonith_watchdog_timeout_ms;
590 bool need_full_refresh = false;
591
592 if(!have_cib_devices) {
593 crm_trace("Skipping updates until we get a full dump");
594 return;
595
596 } else if(msg == NULL) {
597 crm_trace("Missing %s update", event);
598 return;
599 }
600
601
602
603
604 if (local_cib != NULL) {
605 int rc = pcmk_ok;
606 xmlNode *patchset = NULL;
607
608 crm_element_value_int(msg, F_CIB_RC, &rc);
609 if (rc != pcmk_ok) {
610 return;
611 }
612
613 patchset = get_message_xml(msg, F_CIB_UPDATE_RESULT);
614 rc = xml_apply_patchset(local_cib, patchset, TRUE);
615 switch (rc) {
616 case pcmk_ok:
617 case -pcmk_err_old_data:
618 break;
619 case -pcmk_err_diff_resync:
620 case -pcmk_err_diff_failed:
621 crm_notice("[%s] Patch aborted: %s (%d)", event, pcmk_strerror(rc), rc);
622 free_xml(local_cib);
623 local_cib = NULL;
624 break;
625 default:
626 crm_warn("[%s] ABORTED: %s (%d)", event, pcmk_strerror(rc), rc);
627 free_xml(local_cib);
628 local_cib = NULL;
629 }
630 }
631
632 if (local_cib == NULL) {
633 if (fenced_query_cib() != pcmk_rc_ok) {
634 return;
635 }
636 need_full_refresh = true;
637 }
638
639 pcmk__refresh_node_caches_from_cib(local_cib);
640 update_stonith_watchdog_timeout_ms(local_cib);
641
642 if (timeout_ms_saved != stonith_watchdog_timeout_ms) {
643 need_full_refresh = true;
644 }
645
646 if (need_full_refresh) {
647 fencing_topology_init();
648 cib_devices_update();
649 } else {
650
651 update_fencing_topology(event, msg);
652 update_cib_stonith_devices(event, msg);
653 }
654
655 watchdog_device_update();
656 }
657
658 static void
659 init_cib_cache_cb(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
660 {
661 crm_info("Updating device list from CIB");
662 have_cib_devices = TRUE;
663 local_cib = copy_xml(output);
664
665 pcmk__refresh_node_caches_from_cib(local_cib);
666 update_stonith_watchdog_timeout_ms(local_cib);
667
668 fencing_topology_init();
669 cib_devices_update();
670 watchdog_device_update();
671 }
672
673 static void
674 cib_connection_destroy(gpointer user_data)
675 {
676 if (stonith_shutdown_flag) {
677 crm_info("Connection to the CIB manager closed");
678 return;
679 } else {
680 crm_crit("Lost connection to the CIB manager, shutting down");
681 }
682 if (cib_api) {
683 cib_api->cmds->signoff(cib_api);
684 }
685 stonith_shutdown(0);
686 }
687
688
689
690
691
692 void
693 fenced_cib_cleanup(void)
694 {
695 if (cib_api != NULL) {
696 cib_api->cmds->del_notify_callback(cib_api, T_CIB_DIFF_NOTIFY,
697 update_cib_cache_cb);
698 cib__clean_up_connection(&cib_api);
699 }
700 free_xml(local_cib);
701 local_cib = NULL;
702 }
703
704 void
705 setup_cib(void)
706 {
707 int rc, retries = 0;
708
709 cib_api = cib_new();
710 if (cib_api == NULL) {
711 crm_err("No connection to the CIB manager");
712 return;
713 }
714
715 do {
716 sleep(retries);
717 rc = cib_api->cmds->signon(cib_api, CRM_SYSTEM_STONITHD, cib_command);
718 } while (rc == -ENOTCONN && ++retries < 5);
719
720 if (rc != pcmk_ok) {
721 crm_err("Could not connect to the CIB manager: %s (%d)", pcmk_strerror(rc), rc);
722
723 } else if (pcmk_ok !=
724 cib_api->cmds->add_notify_callback(cib_api, T_CIB_DIFF_NOTIFY, update_cib_cache_cb)) {
725 crm_err("Could not set CIB notification callback");
726
727 } else {
728 rc = cib_api->cmds->query(cib_api, NULL, NULL, cib_scope_local);
729 cib_api->cmds->register_callback(cib_api, rc, 120, FALSE, NULL, "init_cib_cache_cb",
730 init_cib_cache_cb);
731 cib_api->cmds->set_connection_dnotify(cib_api, cib_connection_destroy);
732 crm_info("Watching for fencing topology changes");
733 }
734 }