This source file includes following definitions.
- node_has_attr
- add_topology_level
- topology_remove_helper
- remove_topology_level
- register_fencing_topology
- fencing_topology_init
- update_stonith_watchdog_timeout_ms
- cib_devices_update
- update_cib_stonith_devices
- watchdog_device_update
- fenced_query_cib
- 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/common/xml.h>
19
20 #include <crm/cluster/internal.h>
21
22 #include <crm/cib.h>
23 #include <crm/cib/internal.h>
24
25 #include <pacemaker-fenced.h>
26
27 static xmlNode *local_cib = NULL;
28 static cib_t *cib_api = NULL;
29 static bool have_cib_devices = FALSE;
30
31
32
33
34
35
36
37
38
39
40
41 gboolean
42 node_has_attr(const char *node, const char *name, const char *value)
43 {
44 GString *xpath = NULL;
45 xmlNode *match;
46
47 CRM_CHECK((local_cib != NULL) && (node != NULL) && (name != NULL)
48 && (value != NULL), return FALSE);
49
50
51
52
53
54
55 xpath = g_string_sized_new(256);
56 pcmk__g_strcat(xpath,
57 "//" PCMK_XE_NODES "/" PCMK_XE_NODE
58 "[@" PCMK_XA_UNAME "='", node, "']"
59 "/" PCMK_XE_INSTANCE_ATTRIBUTES
60 "/" PCMK_XE_NVPAIR
61 "[@" PCMK_XA_NAME "='", name, "' "
62 "and @" PCMK_XA_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_config_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 = pcmk__xe_create(NULL, PCMK_XE_FENCING_LEVEL);
90
91 crm_xml_add(data, PCMK__XA_ST_ORIGIN, __func__);
92 crm_xml_add_int(data, PCMK_XA_INDEX, level);
93 crm_xml_add(data, PCMK_XA_TARGET, node);
94
95 fenced_unregister_level(data, &desc, &result);
96 fenced_send_config_notification(STONITH_OP_LEVEL_DEL, &result, desc);
97 pcmk__reset_result(&result);
98 pcmk__xml_free(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, PCMK_XA_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 = "//" PCMK_XE_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 #define XPATH_WATCHDOG_TIMEOUT "//" PCMK_XE_NVPAIR \
166 "[@" PCMK_XA_NAME "='" \
167 PCMK_OPT_STONITH_WATCHDOG_TIMEOUT "']"
168
169 static void
170 update_stonith_watchdog_timeout_ms(xmlNode *cib)
171 {
172 long long timeout_ms = 0;
173 xmlNode *stonith_watchdog_xml = NULL;
174 const char *value = NULL;
175
176 stonith_watchdog_xml = get_xpath_object(XPATH_WATCHDOG_TIMEOUT, cib,
177 LOG_NEVER);
178 if (stonith_watchdog_xml) {
179 value = crm_element_value(stonith_watchdog_xml, PCMK_XA_VALUE);
180 }
181 if (value) {
182 timeout_ms = crm_get_msec(value);
183 }
184
185 if (timeout_ms < 0) {
186 timeout_ms = pcmk__auto_stonith_watchdog_timeout();
187 }
188
189 stonith_watchdog_timeout_ms = timeout_ms;
190 }
191
192
193
194
195
196 static void
197 cib_devices_update(void)
198 {
199 GHashTableIter iter;
200 stonith_device_t *device = NULL;
201
202 crm_info("Updating devices to version %s.%s.%s",
203 crm_element_value(local_cib, PCMK_XA_ADMIN_EPOCH),
204 crm_element_value(local_cib, PCMK_XA_EPOCH),
205 crm_element_value(local_cib, PCMK_XA_NUM_UPDATES));
206
207 g_hash_table_iter_init(&iter, device_list);
208 while (g_hash_table_iter_next(&iter, NULL, (void **)&device)) {
209 if (device->cib_registered) {
210 device->dirty = TRUE;
211 }
212 }
213
214
215
216
217 g_list_free_full(stonith_watchdog_targets, free);
218 stonith_watchdog_targets = NULL;
219
220 fenced_scheduler_run(local_cib);
221
222 g_hash_table_iter_init(&iter, device_list);
223 while (g_hash_table_iter_next(&iter, NULL, (void **)&device)) {
224 if (device->dirty) {
225 g_hash_table_iter_remove(&iter);
226 }
227 }
228 }
229
230 static void
231 update_cib_stonith_devices(const char *event, xmlNode * msg)
232 {
233 int format = 1;
234 xmlNode *wrapper = pcmk__xe_first_child(msg, PCMK__XE_CIB_UPDATE_RESULT,
235 NULL, NULL);
236 xmlNode *patchset = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
237 char *reason = NULL;
238
239 CRM_CHECK(patchset != NULL, return);
240 crm_element_value_int(patchset, PCMK_XA_FORMAT, &format);
241
242 if (format != 2) {
243 crm_warn("Unknown patch format: %d", format);
244 return;
245 }
246
247 for (xmlNode *change = pcmk__xe_first_child(patchset, NULL, NULL, NULL);
248 change != NULL; change = pcmk__xe_next(change, NULL)) {
249
250 const char *op = crm_element_value(change, PCMK_XA_OPERATION);
251 const char *xpath = crm_element_value(change, PCMK_XA_PATH);
252 const char *shortpath = NULL;
253
254 if (pcmk__str_eq(op, PCMK_VALUE_MOVE, pcmk__str_null_matches)
255 || (strstr(xpath, "/" PCMK_XE_STATUS) != NULL)) {
256 continue;
257 }
258
259 if (pcmk__str_eq(op, PCMK_VALUE_DELETE, pcmk__str_none)
260 && (strstr(xpath, "/" PCMK_XE_PRIMITIVE) != NULL)) {
261 const char *rsc_id = NULL;
262 char *search = NULL;
263 char *mutable = NULL;
264
265 if ((strstr(xpath, PCMK_XE_INSTANCE_ATTRIBUTES) != NULL)
266 || (strstr(xpath, PCMK_XE_META_ATTRIBUTES) != NULL)) {
267
268 reason = pcmk__str_copy("(meta) attribute deleted from "
269 "resource");
270 break;
271 }
272 mutable = pcmk__str_copy(xpath);
273 rsc_id = strstr(mutable, PCMK_XE_PRIMITIVE "[@" PCMK_XA_ID "=\'");
274 if (rsc_id != NULL) {
275 rsc_id += strlen(PCMK_XE_PRIMITIVE "[@" PCMK_XA_ID "=\'");
276 search = strchr(rsc_id, '\'');
277 }
278 if (search != NULL) {
279 *search = 0;
280 stonith_device_remove(rsc_id, true);
281
282
283 } else {
284 crm_warn("Ignoring malformed CIB update (resource deletion)");
285 }
286 free(mutable);
287
288 } else if (strstr(xpath, "/" PCMK_XE_RESOURCES)
289 || strstr(xpath, "/" PCMK_XE_CONSTRAINTS)
290 || strstr(xpath, "/" PCMK_XE_RSC_DEFAULTS)) {
291 shortpath = strrchr(xpath, '/');
292 pcmk__assert(shortpath != NULL);
293 reason = crm_strdup_printf("%s %s", op, shortpath+1);
294 break;
295 }
296 }
297
298 if (reason != NULL) {
299 crm_info("Updating device list from CIB: %s", reason);
300 cib_devices_update();
301 free(reason);
302 } else {
303 crm_trace("No updates for device list found in CIB");
304 }
305 }
306
307 static void
308 watchdog_device_update(void)
309 {
310 if (stonith_watchdog_timeout_ms > 0) {
311 if (!g_hash_table_lookup(device_list, STONITH_WATCHDOG_ID) &&
312 !stonith_watchdog_targets) {
313
314
315
316 int rc;
317 xmlNode *xml;
318
319 xml = create_device_registration_xml(
320 STONITH_WATCHDOG_ID,
321 st_namespace_internal,
322 STONITH_WATCHDOG_AGENT,
323 NULL,
324
325
326
327 NULL);
328 rc = stonith_device_register(xml, TRUE);
329 pcmk__xml_free(xml);
330 if (rc != pcmk_ok) {
331 rc = pcmk_legacy2rc(rc);
332 exit_code = CRM_EX_FATAL;
333 crm_crit("Cannot register watchdog pseudo fence agent: %s",
334 pcmk_rc_str(rc));
335 stonith_shutdown(0);
336 }
337 }
338
339 } else if (g_hash_table_lookup(device_list, STONITH_WATCHDOG_ID) != NULL) {
340
341 stonith_device_remove(STONITH_WATCHDOG_ID, true);
342 }
343 }
344
345
346
347
348
349
350
351 static int
352 fenced_query_cib(void)
353 {
354 int rc = pcmk_ok;
355
356 crm_trace("Re-requesting full CIB");
357 rc = cib_api->cmds->query(cib_api, NULL, &local_cib, cib_sync_call);
358 rc = pcmk_legacy2rc(rc);
359 if (rc == pcmk_rc_ok) {
360 pcmk__assert(local_cib != NULL);
361 } else {
362 crm_err("Couldn't retrieve the CIB: %s " QB_XS " rc=%d",
363 pcmk_rc_str(rc), rc);
364 }
365 return rc;
366 }
367
368 static void
369 update_fencing_topology(const char *event, xmlNode *msg)
370 {
371 xmlNode *wrapper = pcmk__xe_first_child(msg, PCMK__XE_CIB_UPDATE_RESULT,
372 NULL, NULL);
373 xmlNode *patchset = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
374
375 int format = 1;
376
377 int add[] = { 0, 0, 0 };
378 int del[] = { 0, 0, 0 };
379
380 CRM_CHECK(patchset != NULL, return);
381
382 crm_element_value_int(patchset, PCMK_XA_FORMAT, &format);
383 if (format != 2) {
384 crm_warn("Unknown patch format: %d", format);
385 return;
386 }
387
388 xml_patch_versions(patchset, add, del);
389
390 for (xmlNode *change = pcmk__xe_first_child(patchset, NULL, NULL, NULL);
391 change != NULL; change = pcmk__xe_next(change, NULL)) {
392
393 const char *op = crm_element_value(change, PCMK_XA_OPERATION);
394 const char *xpath = crm_element_value(change, PCMK_XA_PATH);
395
396 if (op == NULL) {
397 continue;
398 }
399
400 if (strstr(xpath, "/" PCMK_XE_FENCING_LEVEL) != NULL) {
401
402 crm_trace("Handling %s operation %d.%d.%d for %s",
403 op, add[0], add[1], add[2], xpath);
404
405 if (strcmp(op, PCMK_VALUE_DELETE) == 0) {
406
407
408
409 crm_info("Re-initializing fencing topology after %s operation "
410 "%d.%d.%d for %s",
411 op, add[0], add[1], add[2], xpath);
412 fencing_topology_init();
413 return;
414 }
415
416 if (strcmp(op, PCMK_VALUE_CREATE) == 0) {
417 add_topology_level(change->children);
418
419 } else if (strcmp(op, PCMK_VALUE_MODIFY) == 0) {
420 xmlNode *match = pcmk__xe_first_child(change,
421 PCMK_XE_CHANGE_RESULT,
422 NULL, NULL);
423
424 if (match != NULL) {
425 remove_topology_level(match->children);
426 add_topology_level(match->children);
427 }
428 }
429 continue;
430 }
431
432 if (strstr(xpath, "/" PCMK_XE_FENCING_TOPOLOGY) != NULL) {
433
434 crm_info("Re-initializing fencing topology after top-level "
435 "%s operation %d.%d.%d for %s",
436 op, add[0], add[1], add[2], xpath);
437 fencing_topology_init();
438 return;
439 }
440
441 if ((strstr(xpath, "/" PCMK_XE_CONFIGURATION) != NULL)
442 && (pcmk__xe_first_child(change, PCMK_XE_FENCING_TOPOLOGY, NULL,
443 NULL) != NULL)
444 && pcmk__str_any_of(op, PCMK_VALUE_CREATE, PCMK_VALUE_DELETE,
445 NULL)) {
446
447
448 crm_info("Re-initializing fencing topology after top-level "
449 "%s operation %d.%d.%d for %s",
450 op, add[0], add[1], add[2], xpath);
451 fencing_topology_init();
452 return;
453 }
454
455 crm_trace("Nothing for us in %s operation %d.%d.%d for %s",
456 op, add[0], add[1], add[2], xpath);
457 }
458 }
459
460 static void
461 update_cib_cache_cb(const char *event, xmlNode * msg)
462 {
463 long long timeout_ms_saved = stonith_watchdog_timeout_ms;
464 bool need_full_refresh = false;
465
466 if(!have_cib_devices) {
467 crm_trace("Skipping updates until we get a full dump");
468 return;
469
470 } else if(msg == NULL) {
471 crm_trace("Missing %s update", event);
472 return;
473 }
474
475
476
477
478 if (local_cib != NULL) {
479 int rc = pcmk_ok;
480 xmlNode *wrapper = NULL;
481 xmlNode *patchset = NULL;
482
483 crm_element_value_int(msg, PCMK__XA_CIB_RC, &rc);
484 if (rc != pcmk_ok) {
485 return;
486 }
487
488 wrapper = pcmk__xe_first_child(msg, PCMK__XE_CIB_UPDATE_RESULT, NULL,
489 NULL);
490 patchset = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
491
492 rc = xml_apply_patchset(local_cib, patchset, TRUE);
493 switch (rc) {
494 case pcmk_ok:
495 case -pcmk_err_old_data:
496 break;
497 case -pcmk_err_diff_resync:
498 case -pcmk_err_diff_failed:
499 crm_notice("[%s] Patch aborted: %s (%d)", event, pcmk_strerror(rc), rc);
500 pcmk__xml_free(local_cib);
501 local_cib = NULL;
502 break;
503 default:
504 crm_warn("[%s] ABORTED: %s (%d)", event, pcmk_strerror(rc), rc);
505 pcmk__xml_free(local_cib);
506 local_cib = NULL;
507 }
508 }
509
510 if (local_cib == NULL) {
511 if (fenced_query_cib() != pcmk_rc_ok) {
512 return;
513 }
514 need_full_refresh = true;
515 }
516
517 pcmk__refresh_node_caches_from_cib(local_cib);
518 update_stonith_watchdog_timeout_ms(local_cib);
519
520 if (timeout_ms_saved != stonith_watchdog_timeout_ms) {
521 need_full_refresh = true;
522 }
523
524 if (need_full_refresh) {
525 fencing_topology_init();
526 cib_devices_update();
527 } else {
528
529 update_fencing_topology(event, msg);
530 update_cib_stonith_devices(event, msg);
531 }
532
533 watchdog_device_update();
534 }
535
536 static void
537 init_cib_cache_cb(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
538 {
539 crm_info("Updating device list from CIB");
540 have_cib_devices = TRUE;
541 local_cib = pcmk__xml_copy(NULL, output);
542
543 pcmk__refresh_node_caches_from_cib(local_cib);
544 update_stonith_watchdog_timeout_ms(local_cib);
545
546 fencing_topology_init();
547 cib_devices_update();
548 watchdog_device_update();
549 }
550
551 static void
552 cib_connection_destroy(gpointer user_data)
553 {
554 if (stonith_shutdown_flag) {
555 crm_info("Connection to the CIB manager closed");
556 return;
557 } else {
558 crm_crit("Lost connection to the CIB manager, shutting down");
559 }
560 if (cib_api) {
561 cib_api->cmds->signoff(cib_api);
562 }
563 stonith_shutdown(0);
564 }
565
566
567
568
569
570 void
571 fenced_cib_cleanup(void)
572 {
573 if (cib_api != NULL) {
574 cib_api->cmds->del_notify_callback(cib_api, PCMK__VALUE_CIB_DIFF_NOTIFY,
575 update_cib_cache_cb);
576 cib__clean_up_connection(&cib_api);
577 }
578 pcmk__xml_free(local_cib);
579 local_cib = NULL;
580 }
581
582 void
583 setup_cib(void)
584 {
585 int rc, retries = 0;
586
587 cib_api = cib_new();
588 if (cib_api == NULL) {
589 crm_err("No connection to the CIB manager");
590 return;
591 }
592
593 do {
594 sleep(retries);
595 rc = cib_api->cmds->signon(cib_api, crm_system_name, cib_command);
596 } while (rc == -ENOTCONN && ++retries < 5);
597
598 if (rc != pcmk_ok) {
599 crm_err("Could not connect to the CIB manager: %s (%d)", pcmk_strerror(rc), rc);
600 return;
601 }
602
603 rc = cib_api->cmds->add_notify_callback(cib_api,
604 PCMK__VALUE_CIB_DIFF_NOTIFY,
605 update_cib_cache_cb);
606 if (rc != pcmk_ok) {
607 crm_err("Could not set CIB notification callback");
608 return;
609 }
610
611 rc = cib_api->cmds->query(cib_api, NULL, NULL, cib_none);
612 cib_api->cmds->register_callback(cib_api, rc, 120, FALSE, NULL,
613 "init_cib_cache_cb", init_cib_cache_cb);
614 cib_api->cmds->set_connection_dnotify(cib_api, cib_connection_destroy);
615 crm_info("Watching for fencing topology changes");
616 }