pacemaker 3.0.1-16e74fc4da
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
st_client.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2025 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 Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11
12#include <stdlib.h>
13#include <stdio.h>
14#include <stdbool.h>
15#include <string.h>
16#include <ctype.h>
17#include <inttypes.h>
18#include <sys/types.h>
19
20#include <glib.h>
21#include <libxml/tree.h> // xmlNode
22#include <libxml/xpath.h> // xmlXPathObject, etc.
23
24#include <crm/crm.h>
25#include <crm/stonith-ng.h>
27#include <crm/common/xml.h>
28
29#include <crm/common/mainloop.h>
30
31#include "fencing_private.h"
32
34
35// Used as stonith_t:st_private
36typedef struct stonith_private_s {
37 char *token;
38 crm_ipc_t *ipc;
39 mainloop_io_t *source;
40 GHashTable *stonith_op_callback_table;
41 GList *notify_list;
42 int notify_refcnt;
43 bool notify_deletes;
44
45 void (*op_callback) (stonith_t * st, stonith_callback_data_t * data);
46
48
49// Used as stonith_event_t:opaque
50struct event_private {
52};
53
54typedef struct stonith_notify_client_s {
55 const char *event;
56 const char *obj_id; /* implement one day */
57 const char *obj_type; /* implement one day */
58 void (*notify) (stonith_t * st, stonith_event_t * e);
59 bool delete;
60
62
63typedef struct stonith_callback_client_s {
64 void (*callback) (stonith_t * st, stonith_callback_data_t * data);
65 const char *id;
66 void *user_data;
67 gboolean only_success;
68 gboolean allow_timeout_updates;
69 struct timer_rec_s *timer;
70
72
73struct notify_blob_s {
74 stonith_t *stonith;
75 xmlNode *xml;
76};
77
78struct timer_rec_s {
79 int call_id;
80 int timeout;
81 guint ref;
83};
84
85typedef int (*stonith_op_t) (const char *, int, const char *, xmlNode *,
86 xmlNode *, xmlNode *, xmlNode **, xmlNode **);
87
88xmlNode *stonith_create_op(int call_id, const char *token, const char *op, xmlNode * data,
89 int call_options);
90static int stonith_send_command(stonith_t *stonith, const char *op,
91 xmlNode *data, xmlNode **output_data,
92 int call_options, int timeout);
93
94static void stonith_connection_destroy(gpointer user_data);
95static void stonith_send_notification(gpointer data, gpointer user_data);
96static int stonith_api_del_notification(stonith_t *stonith,
97 const char *event);
98
107static enum stonith_namespace
108parse_namespace(const char *namespace_s)
109{
110 if (pcmk__str_eq(namespace_s, "any", pcmk__str_null_matches)) {
111 return st_namespace_any;
112 }
113 /* @TODO Is "redhat" still necessary except for stonith_text2namespace()
114 * backward compatibility?
115 */
116 if (pcmk__str_any_of(namespace_s, "redhat", "stonith-ng", NULL)) {
117 return st_namespace_rhcs;
118 }
119 if (pcmk__str_eq(namespace_s, "internal", pcmk__str_none)) {
121 }
122 if (pcmk__str_eq(namespace_s, "heartbeat", pcmk__str_none)) {
123 return st_namespace_lha;
124 }
126}
127
136static const char *
137namespace_text(enum stonith_namespace st_namespace)
138{
139 switch (st_namespace) {
140 case st_namespace_any:
141 return "any";
143 return "stonith-ng";
145 return "internal";
146 case st_namespace_lha:
147 return "heartbeat";
148 default:
149 return "unsupported";
150 }
151}
152
165static enum stonith_namespace
166get_namespace_from_agent(const char *agent)
167{
168 if (stonith__agent_is_rhcs(agent)) {
169 return st_namespace_rhcs;
170 }
171
172#if HAVE_STONITH_STONITH_H
173 if (stonith__agent_is_lha(agent)) {
174 return st_namespace_lha;
175 }
176#endif // HAVE_STONITH_STONITH_H
177
179}
180
181gboolean
183{
184 gboolean rv = FALSE;
185 stonith_t *stonith_api = (st != NULL)? st : stonith__api_new();
186 char *list = NULL;
187
188 if(stonith_api) {
189 if (stonith_api->state == stonith_disconnected) {
190 int rc = stonith_api->cmds->connect(stonith_api, "stonith-api", NULL);
191
192 if (rc != pcmk_ok) {
193 crm_err("Failed connecting to Stonith-API for watchdog-fencing-query.");
194 }
195 }
196
197 if (stonith_api->state != stonith_disconnected) {
198 /* caveat!!!
199 * this might fail when when stonithd is just updating the device-list
200 * probably something we should fix as well for other api-calls */
201 int rc = stonith_api->cmds->list(stonith_api, st_opt_sync_call, STONITH_WATCHDOG_ID, &list, 0);
202 if ((rc != pcmk_ok) || (list == NULL)) {
203 /* due to the race described above it can happen that
204 * we drop in here - so as not to make remote nodes
205 * panic on that answer
206 */
207 if (rc == -ENODEV) {
208 crm_notice("Cluster does not have watchdog fencing device");
209 } else {
210 crm_warn("Could not check for watchdog fencing device: %s",
211 pcmk_strerror(rc));
212 }
213 } else if (list[0] == '\0') {
214 rv = TRUE;
215 } else {
216 GList *targets = stonith__parse_targets(list);
217 rv = pcmk__str_in_list(node, targets, pcmk__str_casei);
218 g_list_free_full(targets, free);
219 }
220 free(list);
221 if (!st) {
222 /* if we're provided the api we still might have done the
223 * connection - but let's assume the caller won't bother
224 */
225 stonith_api->cmds->disconnect(stonith_api);
226 }
227 }
228
229 if (!st) {
230 stonith__api_free(stonith_api);
231 }
232 } else {
233 crm_err("Stonith-API for watchdog-fencing-query couldn't be created.");
234 }
235 crm_trace("Pacemaker assumes node %s %sto do watchdog-fencing.",
236 node, rv?"":"not ");
237 return rv;
238}
239
240gboolean
245
246/* when cycling through the list we don't want to delete items
247 so just mark them and when we know nobody is using the list
248 loop over it to remove the marked items
249 */
250static void
251foreach_notify_entry (stonith_private_t *private,
252 GFunc func,
253 gpointer user_data)
254{
255 private->notify_refcnt++;
256 g_list_foreach(private->notify_list, func, user_data);
257 private->notify_refcnt--;
258 if ((private->notify_refcnt == 0) &&
259 private->notify_deletes) {
260 GList *list_item = private->notify_list;
261
262 private->notify_deletes = FALSE;
263 while (list_item != NULL)
264 {
265 stonith_notify_client_t *list_client = list_item->data;
266 GList *next = g_list_next(list_item);
267
268 if (list_client->delete) {
269 free(list_client);
270 private->notify_list =
271 g_list_delete_link(private->notify_list, list_item);
272 }
273 list_item = next;
274 }
275 }
276}
277
278static void
279stonith_connection_destroy(gpointer user_data)
280{
281 stonith_t *stonith = user_data;
282 stonith_private_t *native = NULL;
283 struct notify_blob_s blob;
284
285 crm_trace("Sending destroyed notification");
286 blob.stonith = stonith;
287 blob.xml = pcmk__xe_create(NULL, PCMK__XE_NOTIFY);
288
289 native = stonith->st_private;
290 native->ipc = NULL;
291 native->source = NULL;
292
293 free(native->token); native->token = NULL;
294 stonith->state = stonith_disconnected;
297
298 foreach_notify_entry(native, stonith_send_notification, &blob);
299 pcmk__xml_free(blob.xml);
300}
301
302xmlNode *
304 const char *agent,
305 const stonith_key_value_t *params,
306 const char *rsc_provides)
307{
309 xmlNode *args = pcmk__xe_create(data, PCMK__XE_ATTRIBUTES);
310
311#if HAVE_STONITH_STONITH_H
312 if (standard == st_namespace_any) {
313 standard = get_namespace_from_agent(agent);
314 }
315 if (standard == st_namespace_lha) {
316 hash2field((gpointer) "plugin", (gpointer) agent, args);
317 agent = "fence_legacy";
318 }
319#endif
320
324 if ((standard != st_namespace_any) && (standard != st_namespace_invalid)) {
325 crm_xml_add(data, PCMK__XA_NAMESPACE, namespace_text(standard));
326 }
327 if (rsc_provides) {
328 crm_xml_add(data, PCMK__XA_RSC_PROVIDES, rsc_provides);
329 }
330
331 for (; params; params = params->next) {
332 hash2field((gpointer) params->key, (gpointer) params->value, args);
333 }
334
335 return data;
336}
337
338static int
339stonith_api_register_device(stonith_t *st, int call_options,
340 const char *id, const char *namespace_s,
341 const char *agent,
342 const stonith_key_value_t *params)
343{
344 int rc = 0;
345 xmlNode *data = NULL;
346
347 data = create_device_registration_xml(id, parse_namespace(namespace_s),
348 agent, params, NULL);
349
350 rc = stonith_send_command(st, STONITH_OP_DEVICE_ADD, data, NULL, call_options, 0);
352
353 return rc;
354}
355
356static int
357stonith_api_remove_device(stonith_t * st, int call_options, const char *name)
358{
359 int rc = 0;
360 xmlNode *data = NULL;
361
365 rc = stonith_send_command(st, STONITH_OP_DEVICE_DEL, data, NULL, call_options, 0);
367
368 return rc;
369}
370
371static int
372stonith_api_remove_level_full(stonith_t *st, int options,
373 const char *node, const char *pattern,
374 const char *attr, const char *value, int level)
375{
376 int rc = 0;
377 xmlNode *data = NULL;
378
379 CRM_CHECK(node || pattern || (attr && value), return -EINVAL);
380
383
384 if (node) {
386
387 } else if (pattern) {
389
390 } else {
393 }
394
396 rc = stonith_send_command(st, STONITH_OP_LEVEL_DEL, data, NULL, options, 0);
398
399 return rc;
400}
401
402static int
403stonith_api_remove_level(stonith_t * st, int options, const char *node, int level)
404{
405 return stonith_api_remove_level_full(st, options, node,
406 NULL, NULL, NULL, level);
407}
408
424xmlNode *
425create_level_registration_xml(const char *node, const char *pattern,
426 const char *attr, const char *value,
427 int level, const stonith_key_value_t *device_list)
428{
429 GString *list = NULL;
430 xmlNode *data;
431
432 CRM_CHECK(node || pattern || (attr && value), return NULL);
433
435
439
440 if (node) {
442
443 } else if (pattern) {
445
446 } else {
449 }
450
451 for (; device_list; device_list = device_list->next) {
452 pcmk__add_separated_word(&list, 1024, device_list->value, ",");
453 }
454
455 if (list != NULL) {
456 crm_xml_add(data, PCMK_XA_DEVICES, (const char *) list->str);
457 g_string_free(list, TRUE);
458 }
459 return data;
460}
461
462static int
463stonith_api_register_level_full(stonith_t *st, int options, const char *node,
464 const char *pattern, const char *attr,
465 const char *value, int level,
466 const stonith_key_value_t *device_list)
467{
468 int rc = 0;
469 xmlNode *data = create_level_registration_xml(node, pattern, attr, value,
470 level, device_list);
471 CRM_CHECK(data != NULL, return -EINVAL);
472
473 rc = stonith_send_command(st, STONITH_OP_LEVEL_ADD, data, NULL, options, 0);
475
476 return rc;
477}
478
479static int
480stonith_api_register_level(stonith_t * st, int options, const char *node, int level,
481 const stonith_key_value_t * device_list)
482{
483 return stonith_api_register_level_full(st, options, node, NULL, NULL, NULL,
484 level, device_list);
485}
486
487static int
488stonith_api_device_list(stonith_t *stonith, int call_options,
489 const char *namespace_s, stonith_key_value_t **devices,
490 int timeout)
491{
492 int count = 0;
493 enum stonith_namespace ns = parse_namespace(namespace_s);
494
495 if (devices == NULL) {
496 crm_err("Parameter error: stonith_api_device_list");
497 return -EFAULT;
498 }
499
500#if HAVE_STONITH_STONITH_H
501 // Include Linux-HA agents if requested
502 if ((ns == st_namespace_any) || (ns == st_namespace_lha)) {
503 count += stonith__list_lha_agents(devices);
504 }
505#endif
506
507 // Include Red Hat agents if requested
508 if ((ns == st_namespace_any) || (ns == st_namespace_rhcs)) {
509 count += stonith__list_rhcs_agents(devices);
510 }
511
512 return count;
513}
514
515// See stonith_api_operations_t:metadata() documentation
516static int
517stonith_api_device_metadata(stonith_t *stonith, int call_options,
518 const char *agent, const char *namespace_s,
519 char **output, int timeout_sec)
520{
521 /* By executing meta-data directly, we can get it from stonith_admin when
522 * the cluster is not running, which is important for higher-level tools.
523 */
524
525 enum stonith_namespace ns = get_namespace_from_agent(agent);
526
527 if (timeout_sec <= 0) {
528 timeout_sec = PCMK_DEFAULT_ACTION_TIMEOUT_MS;
529 }
530
531 crm_trace("Looking up metadata for %s agent %s", namespace_text(ns), agent);
532
533 switch (ns) {
535 return stonith__rhcs_metadata(agent, timeout_sec, output);
536
537#if HAVE_STONITH_STONITH_H
538 case st_namespace_lha:
539 return stonith__lha_metadata(agent, timeout_sec, output);
540#endif
541
542 default:
543 crm_err("Can't get fence agent '%s' meta-data: No such agent",
544 agent);
545 break;
546 }
547 return -ENODEV;
548}
549
550static int
551stonith_api_query(stonith_t * stonith, int call_options, const char *target,
552 stonith_key_value_t ** devices, int timeout)
553{
554 int rc = 0, lpc = 0, max = 0;
555
556 xmlNode *data = NULL;
557 xmlNode *output = NULL;
558 xmlXPathObject *xpathObj = NULL;
559
560 CRM_CHECK(devices != NULL, return -EINVAL);
561
566 rc = stonith_send_command(stonith, STONITH_OP_QUERY, data, &output, call_options, timeout);
567
568 if (rc < 0) {
569 return rc;
570 }
571
572 xpathObj = pcmk__xpath_search(output->doc, "//*[@" PCMK_XA_AGENT "]");
573 if (xpathObj) {
574 max = pcmk__xpath_num_results(xpathObj);
575
576 for (lpc = 0; lpc < max; lpc++) {
577 xmlNode *match = pcmk__xpath_result(xpathObj, lpc);
578
579 CRM_LOG_ASSERT(match != NULL);
580 if(match != NULL) {
581 const char *match_id = crm_element_value(match, PCMK_XA_ID);
582 xmlChar *match_path = xmlGetNodePath(match);
583
584 crm_info("//*[@" PCMK_XA_AGENT "][%d] = %s", lpc, match_path);
585 free(match_path);
586 *devices = stonith__key_value_add(*devices, NULL, match_id);
587 }
588 }
589
590 xmlXPathFreeObject(xpathObj);
591 }
592
593 pcmk__xml_free(output);
595 return max;
596}
597
610static int
611stonith_api_call(stonith_t *stonith, int call_options, const char *id,
612 const char *action, const char *target, int timeout_sec,
613 xmlNode **output)
614{
615 int rc = 0;
616 xmlNode *data = NULL;
617
623
624 rc = stonith_send_command(stonith, STONITH_OP_EXEC, data, output,
625 call_options, timeout_sec);
627
628 return rc;
629}
630
631static int
632stonith_api_list(stonith_t * stonith, int call_options, const char *id, char **list_info,
633 int timeout)
634{
635 int rc;
636 xmlNode *output = NULL;
637
638 rc = stonith_api_call(stonith, call_options, id, PCMK_ACTION_LIST, NULL,
639 timeout, &output);
640
641 if (output && list_info) {
642 const char *list_str;
643
644 list_str = crm_element_value(output, PCMK__XA_ST_OUTPUT);
645
646 if (list_str) {
647 *list_info = strdup(list_str);
648 }
649 }
650
651 if (output) {
652 pcmk__xml_free(output);
653 }
654
655 return rc;
656}
657
658static int
659stonith_api_monitor(stonith_t * stonith, int call_options, const char *id, int timeout)
660{
661 return stonith_api_call(stonith, call_options, id, PCMK_ACTION_MONITOR,
662 NULL, timeout, NULL);
663}
664
665static int
666stonith_api_status(stonith_t * stonith, int call_options, const char *id, const char *port,
667 int timeout)
668{
669 return stonith_api_call(stonith, call_options, id, PCMK_ACTION_STATUS, port,
670 timeout, NULL);
671}
672
673static int
674stonith_api_fence_with_delay(stonith_t * stonith, int call_options, const char *node,
675 const char *action, int timeout, int tolerance, int delay)
676{
677 int rc = 0;
678 xmlNode *data = NULL;
679
680 data = pcmk__xe_create(NULL, __func__);
686
687 rc = stonith_send_command(stonith, STONITH_OP_FENCE, data, NULL, call_options, timeout);
689
690 return rc;
691}
692
693static int
694stonith_api_fence(stonith_t * stonith, int call_options, const char *node, const char *action,
695 int timeout, int tolerance)
696{
697 return stonith_api_fence_with_delay(stonith, call_options, node, action,
698 timeout, tolerance, 0);
699}
700
701static int
702stonith_api_confirm(stonith_t * stonith, int call_options, const char *target)
703{
705 return stonith_api_fence(stonith, call_options, target, PCMK_ACTION_OFF, 0,
706 0);
707}
708
709static int
710stonith_api_history(stonith_t * stonith, int call_options, const char *node,
711 stonith_history_t ** history, int timeout)
712{
713 int rc = 0;
714 xmlNode *data = NULL;
715 xmlNode *output = NULL;
716 stonith_history_t *last = NULL;
717
718 *history = NULL;
719
720 if (node) {
721 data = pcmk__xe_create(NULL, __func__);
723 }
724
725 stonith__set_call_options(call_options, node, st_opt_sync_call);
726 rc = stonith_send_command(stonith, STONITH_OP_FENCE_HISTORY, data, &output,
727 call_options, timeout);
729
730 if (rc == 0) {
731 xmlNode *op = NULL;
732 xmlNode *reply = pcmk__xpath_find_one(output->doc,
734 LOG_NEVER);
735
736 for (op = pcmk__xe_first_child(reply, NULL, NULL, NULL); op != NULL;
737 op = pcmk__xe_next(op, NULL)) {
739 long long completed;
740 long long completed_nsec = 0L;
741
742 kvp = pcmk__assert_alloc(1, sizeof(stonith_history_t));
748 crm_element_value_ll(op, PCMK__XA_ST_DATE, &completed);
749 kvp->completed = (time_t) completed;
750 crm_element_value_ll(op, PCMK__XA_ST_DATE_NSEC, &completed_nsec);
751 kvp->completed_nsec = completed_nsec;
754
755 if (last) {
756 last->next = kvp;
757 } else {
758 *history = kvp;
759 }
760 last = kvp;
761 }
762 }
763
764 pcmk__xml_free(output);
765
766 return rc;
767}
768
775void
777{
778 /* @COMPAT Drop "next" member of stonith_history_t, use a GList or GSList,
779 * and use the appropriate free function (while ensuring the members get
780 * freed)
781 */
782 while (head != NULL) {
783 stonith_history_t *next = head->next;
784
785 free(head->target);
786 free(head->action);
787 free(head->origin);
788 free(head->delegate);
789 free(head->client);
790 free(head->exit_reason);
791 free(head);
792 head = next;
793 }
794}
795
796static gint
797stonithlib_GCompareFunc(gconstpointer a, gconstpointer b)
798{
799 int rc = 0;
800 const stonith_notify_client_t *a_client = a;
801 const stonith_notify_client_t *b_client = b;
802
803 if (a_client->delete || b_client->delete) {
804 /* make entries marked for deletion not findable */
805 return -1;
806 }
807 CRM_CHECK(a_client->event != NULL && b_client->event != NULL, return 0);
808 rc = strcmp(a_client->event, b_client->event);
809 if (rc == 0) {
810 if (a_client->notify == NULL || b_client->notify == NULL) {
811 return 0;
812
813 } else if (a_client->notify == b_client->notify) {
814 return 0;
815
816 } else if (((long)a_client->notify) < ((long)b_client->notify)) {
817 crm_err("callbacks for %s are not equal: %p vs. %p",
818 a_client->event, a_client->notify, b_client->notify);
819 return -1;
820 }
821 crm_err("callbacks for %s are not equal: %p vs. %p",
822 a_client->event, a_client->notify, b_client->notify);
823 return 1;
824 }
825 return rc;
826}
827
828xmlNode *
829stonith_create_op(int call_id, const char *token, const char *op, xmlNode * data, int call_options)
830{
831 xmlNode *op_msg = NULL;
832
833 CRM_CHECK(token != NULL, return NULL);
834
837 crm_xml_add(op_msg, PCMK__XA_ST_OP, op);
838 crm_xml_add_int(op_msg, PCMK__XA_ST_CALLID, call_id);
839 crm_trace("Sending call options: %.8lx, %d", (long)call_options, call_options);
840 crm_xml_add_int(op_msg, PCMK__XA_ST_CALLOPT, call_options);
841
842 if (data != NULL) {
843 xmlNode *wrapper = pcmk__xe_create(op_msg, PCMK__XE_ST_CALLDATA);
844
845 pcmk__xml_copy(wrapper, data);
846 }
847
848 return op_msg;
849}
850
851static void
852stonith_destroy_op_callback(gpointer data)
853{
855
856 if (blob->timer && blob->timer->ref > 0) {
857 g_source_remove(blob->timer->ref);
858 }
859 free(blob->timer);
860 free(blob);
861}
862
863static int
864stonith_api_signoff(stonith_t * stonith)
865{
866 stonith_private_t *native = stonith->st_private;
867
868 crm_debug("Disconnecting from the fencer");
869
870 if (native->source != NULL) {
871 /* Attached to mainloop */
872 mainloop_del_ipc_client(native->source);
873 native->source = NULL;
874 native->ipc = NULL;
875
876 } else if (native->ipc) {
877 /* Not attached to mainloop */
878 crm_ipc_t *ipc = native->ipc;
879
880 native->ipc = NULL;
881 crm_ipc_close(ipc);
882 crm_ipc_destroy(ipc);
883 }
884
885 free(native->token); native->token = NULL;
886 stonith->state = stonith_disconnected;
887 return pcmk_ok;
888}
889
890static int
891stonith_api_del_callback(stonith_t * stonith, int call_id, bool all_callbacks)
892{
893 stonith_private_t *private = stonith->st_private;
894
895 if (all_callbacks) {
896 private->op_callback = NULL;
897 g_hash_table_destroy(private->stonith_op_callback_table);
898 private->stonith_op_callback_table = pcmk__intkey_table(stonith_destroy_op_callback);
899
900 } else if (call_id == 0) {
901 private->op_callback = NULL;
902
903 } else {
904 pcmk__intkey_table_remove(private->stonith_op_callback_table, call_id);
905 }
906 return pcmk_ok;
907}
908
920static void
921invoke_fence_action_callback(stonith_t *st, int call_id,
923 void *userdata,
924 void (*callback) (stonith_t *st,
926{
928
929 data.call_id = call_id;
931 data.userdata = userdata;
932 data.opaque = (void *) result;
933
934 callback(st, &data);
935}
936
948static void
949invoke_registered_callbacks(stonith_t *stonith, const xmlNode *msg, int call_id)
950{
951 stonith_private_t *private = NULL;
952 stonith_callback_client_t *cb_info = NULL;
954
955 CRM_CHECK(stonith != NULL, return);
956 CRM_CHECK(stonith->st_private != NULL, return);
957
958 private = stonith->st_private;
959
960 if (msg == NULL) {
961 // Fencer didn't reply in time
963 "Fencer accepted request but did not reply in time");
964 CRM_LOG_ASSERT(call_id > 0);
965
966 } else {
967 // We have the fencer reply
968 if ((crm_element_value_int(msg, PCMK__XA_ST_CALLID, &call_id) != 0)
969 || (call_id <= 0)) {
970 crm_log_xml_warn(msg, "Bad fencer reply");
971 }
973 }
974
975 if (call_id > 0) {
976 cb_info = pcmk__intkey_table_lookup(private->stonith_op_callback_table,
977 call_id);
978 }
979
980 if ((cb_info != NULL) && (cb_info->callback != NULL)
981 && (pcmk__result_ok(&result) || !(cb_info->only_success))) {
982 crm_trace("Invoking callback %s for call %d",
983 pcmk__s(cb_info->id, "without ID"), call_id);
984 invoke_fence_action_callback(stonith, call_id, &result,
985 cb_info->user_data, cb_info->callback);
986
987 } else if ((private->op_callback == NULL) && !pcmk__result_ok(&result)) {
988 crm_warn("Fencing action without registered callback failed: %d (%s%s%s)",
990 pcmk_exec_status_str(result.execution_status),
991 ((result.exit_reason == NULL)? "" : ": "),
992 ((result.exit_reason == NULL)? "" : result.exit_reason));
993 crm_log_xml_debug(msg, "Failed fence update");
994 }
995
996 if (private->op_callback != NULL) {
997 crm_trace("Invoking global callback for call %d", call_id);
998 invoke_fence_action_callback(stonith, call_id, &result, NULL,
999 private->op_callback);
1000 }
1001
1002 if (cb_info != NULL) {
1003 stonith_api_del_callback(stonith, call_id, FALSE);
1004 }
1006}
1007
1008static gboolean
1009stonith_async_timeout_handler(gpointer data)
1010{
1011 struct timer_rec_s *timer = data;
1012
1013 crm_err("Async call %d timed out after %dms", timer->call_id, timer->timeout);
1014 invoke_registered_callbacks(timer->stonith, NULL, timer->call_id);
1015
1016 /* Always return TRUE, never remove the handler
1017 * We do that in stonith_del_callback()
1018 */
1019 return TRUE;
1020}
1021
1022static void
1023set_callback_timeout(stonith_callback_client_t * callback, stonith_t * stonith, int call_id,
1024 int timeout)
1025{
1026 struct timer_rec_s *async_timer = callback->timer;
1027
1028 if (timeout <= 0) {
1029 return;
1030 }
1031
1032 if (!async_timer) {
1033 async_timer = pcmk__assert_alloc(1, sizeof(struct timer_rec_s));
1034 callback->timer = async_timer;
1035 }
1036
1037 async_timer->stonith = stonith;
1038 async_timer->call_id = call_id;
1039 /* Allow a fair bit of grace to allow the server to tell us of a timeout
1040 * This is only a fallback
1041 */
1042 async_timer->timeout = (timeout + 60) * 1000;
1043 if (async_timer->ref) {
1044 g_source_remove(async_timer->ref);
1045 }
1046 async_timer->ref =
1047 pcmk__create_timer(async_timer->timeout, stonith_async_timeout_handler,
1048 async_timer);
1049}
1050
1051static void
1052update_callback_timeout(int call_id, int timeout, stonith_t * st)
1053{
1054 stonith_callback_client_t *callback = NULL;
1055 stonith_private_t *private = st->st_private;
1056
1057 callback = pcmk__intkey_table_lookup(private->stonith_op_callback_table,
1058 call_id);
1059 if (!callback || !callback->allow_timeout_updates) {
1060 return;
1061 }
1062
1063 set_callback_timeout(callback, st, call_id, timeout);
1064}
1065
1066static int
1067stonith_dispatch_internal(const char *buffer, ssize_t length, gpointer userdata)
1068{
1069 const char *type = NULL;
1070 struct notify_blob_s blob;
1071
1072 stonith_t *st = userdata;
1073 stonith_private_t *private = NULL;
1074
1075 pcmk__assert(st != NULL);
1076 private = st->st_private;
1077
1078 blob.stonith = st;
1079 blob.xml = pcmk__xml_parse(buffer);
1080 if (blob.xml == NULL) {
1081 crm_warn("Received malformed message from fencer: %s", buffer);
1082 return 0;
1083 }
1084
1085 /* do callbacks */
1086 type = crm_element_value(blob.xml, PCMK__XA_T);
1087 crm_trace("Activating %s callbacks...", type);
1088
1089 if (pcmk__str_eq(type, PCMK__VALUE_STONITH_NG, pcmk__str_none)) {
1090 invoke_registered_callbacks(st, blob.xml, 0);
1091
1092 } else if (pcmk__str_eq(type, PCMK__VALUE_ST_NOTIFY, pcmk__str_none)) {
1093 foreach_notify_entry(private, stonith_send_notification, &blob);
1094
1095 } else if (pcmk__str_eq(type, PCMK__VALUE_ST_ASYNC_TIMEOUT_VALUE,
1096 pcmk__str_none)) {
1097 int call_id = 0;
1098 int timeout = 0;
1099
1101 crm_element_value_int(blob.xml, PCMK__XA_ST_CALLID, &call_id);
1102
1103 update_callback_timeout(call_id, timeout, st);
1104 } else {
1105 crm_err("Unknown message type: %s", type);
1106 crm_log_xml_warn(blob.xml, "BadReply");
1107 }
1108
1109 pcmk__xml_free(blob.xml);
1110 return 1;
1111}
1112
1113static int
1114stonith_api_signon(stonith_t * stonith, const char *name, int *stonith_fd)
1115{
1116 int rc = pcmk_ok;
1117 stonith_private_t *native = NULL;
1118 const char *display_name = name? name : "client";
1119
1120 struct ipc_client_callbacks st_callbacks = {
1121 .dispatch = stonith_dispatch_internal,
1122 .destroy = stonith_connection_destroy
1123 };
1124
1125 CRM_CHECK(stonith != NULL, return -EINVAL);
1126
1127 native = stonith->st_private;
1128 pcmk__assert(native != NULL);
1129
1130 crm_debug("Attempting fencer connection by %s with%s mainloop",
1131 display_name, (stonith_fd? "out" : ""));
1132
1134 if (stonith_fd) {
1135 /* No mainloop */
1136 native->ipc = crm_ipc_new("stonith-ng", 0);
1137 if (native->ipc != NULL) {
1138 rc = pcmk__connect_generic_ipc(native->ipc);
1139 if (rc == pcmk_rc_ok) {
1140 rc = pcmk__ipc_fd(native->ipc, stonith_fd);
1141 if (rc != pcmk_rc_ok) {
1142 crm_debug("Couldn't get file descriptor for IPC: %s",
1143 pcmk_rc_str(rc));
1144 }
1145 }
1146 if (rc != pcmk_rc_ok) {
1147 crm_ipc_close(native->ipc);
1148 crm_ipc_destroy(native->ipc);
1149 native->ipc = NULL;
1150 }
1151 }
1152
1153 } else {
1154 /* With mainloop */
1155 native->source =
1156 mainloop_add_ipc_client("stonith-ng", G_PRIORITY_MEDIUM, 0, stonith, &st_callbacks);
1157 native->ipc = mainloop_get_ipc_client(native->source);
1158 }
1159
1160 if (native->ipc == NULL) {
1161 rc = -ENOTCONN;
1162 } else {
1163 xmlNode *reply = NULL;
1164 xmlNode *hello = pcmk__xe_create(NULL, PCMK__XE_STONITH_COMMAND);
1165
1169 rc = crm_ipc_send(native->ipc, hello, crm_ipc_client_response, -1, &reply);
1170
1171 if (rc < 0) {
1172 crm_debug("Couldn't register with the fencer: %s "
1173 QB_XS " rc=%d", pcmk_strerror(rc), rc);
1174 rc = -ECOMM;
1175
1176 } else if (reply == NULL) {
1177 crm_debug("Couldn't register with the fencer: no reply");
1178 rc = -EPROTO;
1179
1180 } else {
1181 const char *msg_type = crm_element_value(reply, PCMK__XA_ST_OP);
1182
1183 native->token = crm_element_value_copy(reply, PCMK__XA_ST_CLIENTID);
1184 if (!pcmk__str_eq(msg_type, CRM_OP_REGISTER, pcmk__str_none)) {
1185 crm_debug("Couldn't register with the fencer: invalid reply type '%s'",
1186 (msg_type? msg_type : "(missing)"));
1187 crm_log_xml_debug(reply, "Invalid fencer reply");
1188 rc = -EPROTO;
1189
1190 } else if (native->token == NULL) {
1191 crm_debug("Couldn't register with the fencer: no token in reply");
1192 crm_log_xml_debug(reply, "Invalid fencer reply");
1193 rc = -EPROTO;
1194
1195 } else {
1196 crm_debug("Connection to fencer by %s succeeded (registration token: %s)",
1197 display_name, native->token);
1198 rc = pcmk_ok;
1199 }
1200 }
1201
1202 pcmk__xml_free(reply);
1203 pcmk__xml_free(hello);
1204 }
1205
1206 if (rc != pcmk_ok) {
1207 crm_debug("Connection attempt to fencer by %s failed: %s "
1208 QB_XS " rc=%d", display_name, pcmk_strerror(rc), rc);
1209 stonith->cmds->disconnect(stonith);
1210 }
1211 return rc;
1212}
1213
1214static int
1215stonith_set_notification(stonith_t * stonith, const char *callback, int enabled)
1216{
1217 int rc = pcmk_ok;
1218 xmlNode *notify_msg = pcmk__xe_create(NULL, __func__);
1219 stonith_private_t *native = stonith->st_private;
1220
1221 if (stonith->state != stonith_disconnected) {
1222
1224 if (enabled) {
1225 crm_xml_add(notify_msg, PCMK__XA_ST_NOTIFY_ACTIVATE, callback);
1226 } else {
1227 crm_xml_add(notify_msg, PCMK__XA_ST_NOTIFY_DEACTIVATE, callback);
1228 }
1229
1230 rc = crm_ipc_send(native->ipc, notify_msg, crm_ipc_client_response, -1, NULL);
1231 if (rc < 0) {
1232 crm_perror(LOG_DEBUG, "Couldn't register for fencing notifications: %d", rc);
1233 rc = -ECOMM;
1234 } else {
1235 rc = pcmk_ok;
1236 }
1237 }
1238
1239 pcmk__xml_free(notify_msg);
1240 return rc;
1241}
1242
1243static int
1244stonith_api_add_notification(stonith_t * stonith, const char *event,
1245 void (*callback) (stonith_t * stonith, stonith_event_t * e))
1246{
1247 GList *list_item = NULL;
1248 stonith_notify_client_t *new_client = NULL;
1249 stonith_private_t *private = NULL;
1250
1251 private = stonith->st_private;
1252 crm_trace("Adding callback for %s events (%d)", event, g_list_length(private->notify_list));
1253
1254 new_client = pcmk__assert_alloc(1, sizeof(stonith_notify_client_t));
1255 new_client->event = event;
1256 new_client->notify = callback;
1257
1258 list_item = g_list_find_custom(private->notify_list, new_client, stonithlib_GCompareFunc);
1259
1260 if (list_item != NULL) {
1261 crm_warn("Callback already present");
1262 free(new_client);
1263 return -ENOTUNIQ;
1264
1265 } else {
1266 private->notify_list = g_list_append(private->notify_list, new_client);
1267
1268 stonith_set_notification(stonith, event, 1);
1269
1270 crm_trace("Callback added (%d)", g_list_length(private->notify_list));
1271 }
1272 return pcmk_ok;
1273}
1274
1275static void
1276del_notify_entry(gpointer data, gpointer user_data)
1277{
1279 stonith_t * stonith = user_data;
1280
1281 if (!entry->delete) {
1282 crm_debug("Removing callback for %s events", entry->event);
1283 stonith_api_del_notification(stonith, entry->event);
1284 }
1285}
1286
1287static int
1288stonith_api_del_notification(stonith_t * stonith, const char *event)
1289{
1290 GList *list_item = NULL;
1291 stonith_notify_client_t *new_client = NULL;
1292 stonith_private_t *private = stonith->st_private;
1293
1294 if (event == NULL) {
1295 foreach_notify_entry(private, del_notify_entry, stonith);
1296 crm_trace("Removed callback");
1297
1298 return pcmk_ok;
1299 }
1300
1301 crm_debug("Removing callback for %s events", event);
1302
1303 new_client = pcmk__assert_alloc(1, sizeof(stonith_notify_client_t));
1304 new_client->event = event;
1305 new_client->notify = NULL;
1306
1307 list_item = g_list_find_custom(private->notify_list, new_client, stonithlib_GCompareFunc);
1308
1309 stonith_set_notification(stonith, event, 0);
1310
1311 if (list_item != NULL) {
1312 stonith_notify_client_t *list_client = list_item->data;
1313
1314 if (private->notify_refcnt) {
1315 list_client->delete = TRUE;
1316 private->notify_deletes = TRUE;
1317 } else {
1318 private->notify_list = g_list_remove(private->notify_list, list_client);
1319 free(list_client);
1320 }
1321
1322 crm_trace("Removed callback");
1323
1324 } else {
1325 crm_trace("Callback not present");
1326 }
1327 free(new_client);
1328 return pcmk_ok;
1329}
1330
1331static int
1332stonith_api_add_callback(stonith_t * stonith, int call_id, int timeout, int options,
1333 void *user_data, const char *callback_name,
1334 void (*callback) (stonith_t * st, stonith_callback_data_t * data))
1335{
1336 stonith_callback_client_t *blob = NULL;
1337 stonith_private_t *private = NULL;
1338
1339 CRM_CHECK(stonith != NULL, return -EINVAL);
1340 CRM_CHECK(stonith->st_private != NULL, return -EINVAL);
1341 private = stonith->st_private;
1342
1343 if (call_id == 0) { // Add global callback
1344 private->op_callback = callback;
1345
1346 } else if (call_id < 0) { // Call failed immediately, so call callback now
1347 if (!(options & st_opt_report_only_success)) {
1349
1350 crm_trace("Call failed, calling %s: %s", callback_name, pcmk_strerror(call_id));
1352 stonith__legacy2status(call_id), NULL);
1353 invoke_fence_action_callback(stonith, call_id, &result,
1354 user_data, callback);
1355 } else {
1356 crm_warn("Fencer call failed: %s", pcmk_strerror(call_id));
1357 }
1358 return FALSE;
1359 }
1360
1362 blob->id = callback_name;
1363 blob->only_success = (options & st_opt_report_only_success) ? TRUE : FALSE;
1364 blob->user_data = user_data;
1365 blob->callback = callback;
1366 blob->allow_timeout_updates = (options & st_opt_timeout_updates) ? TRUE : FALSE;
1367
1368 if (timeout > 0) {
1369 set_callback_timeout(blob, stonith, call_id, timeout);
1370 }
1371
1372 pcmk__intkey_table_insert(private->stonith_op_callback_table, call_id,
1373 blob);
1374 crm_trace("Added callback to %s for call %d", callback_name, call_id);
1375
1376 return TRUE;
1377}
1378
1386static xmlNode *
1387get_event_data_xml(xmlNode *msg, const char *ntype)
1388{
1389 char *data_addr = crm_strdup_printf("//%s", ntype);
1390 xmlNode *data = pcmk__xpath_find_one(msg->doc, data_addr, LOG_DEBUG);
1391
1392 free(data_addr);
1393 return data;
1394}
1395
1396/*
1397 <notify t="st_notify" subt="st_device_register" st_op="st_device_register" st_rc="0" >
1398 <st_calldata >
1399 <stonith_command t="stonith-ng" st_async_id="088fb640-431a-48b9-b2fc-c4ff78d0a2d9" st_op="st_device_register" st_callid="2" st_callopt="4096" st_timeout="0" st_clientid="088fb640-431a-48b9-b2fc-c4ff78d0a2d9" st_clientname="cts-fence-helper" >
1400 <st_calldata >
1401 <st_device_id id="test-id" origin="create_device_registration_xml" agent="fence_virsh" namespace="stonith-ng" >
1402 <attributes ipaddr="localhost" pcmk-portmal="some-host=pcmk-1 pcmk-3=3,4" login="root" identity_file="/root/.ssh/id_dsa" />
1403 </st_device_id>
1404 </st_calldata>
1405 </stonith_command>
1406 </st_calldata>
1407 </notify>
1408
1409 <notify t="st_notify" subt="st_notify_fence" st_op="st_notify_fence" st_rc="0" >
1410 <st_calldata >
1411 <st_notify_fence st_rc="0" st_target="some-host" st_op="st_fence" st_delegate="test-id" st_origin="61dd7759-e229-4be7-b1f8-ef49dd14d9f0" />
1412 </st_calldata>
1413 </notify>
1414*/
1415static stonith_event_t *
1416xml_to_event(xmlNode *msg)
1417{
1419 struct event_private *event_private = NULL;
1420
1421 event->opaque = pcmk__assert_alloc(1, sizeof(struct event_private));
1422 event_private = (struct event_private *) event->opaque;
1423
1424 crm_log_xml_trace(msg, "stonith_notify");
1425
1426 // All notification types have the operation result and notification subtype
1427 stonith__xe_get_result(msg, &event_private->result);
1428 event->operation = crm_element_value_copy(msg, PCMK__XA_ST_OP);
1429
1430 // @COMPAT The API originally provided the result as a legacy return code
1431 event->result = pcmk_rc2legacy(stonith__result2rc(&event_private->result));
1432
1433 // Some notification subtypes have additional information
1434
1435 if (pcmk__str_eq(event->operation, PCMK__VALUE_ST_NOTIFY_FENCE,
1436 pcmk__str_none)) {
1437 xmlNode *data = get_event_data_xml(msg, event->operation);
1438
1439 if (data == NULL) {
1440 crm_err("No data for %s event", event->operation);
1441 crm_log_xml_notice(msg, "BadEvent");
1442 } else {
1444 event->action = crm_element_value_copy(data,
1447 event->executioner = crm_element_value_copy(data,
1450 event->client_origin =
1453 }
1454
1455 } else if (pcmk__str_any_of(event->operation,
1458 NULL)) {
1459 xmlNode *data = get_event_data_xml(msg, event->operation);
1460
1461 if (data == NULL) {
1462 crm_err("No data for %s event", event->operation);
1463 crm_log_xml_notice(msg, "BadEvent");
1464 } else {
1466 }
1467 }
1468
1469 return event;
1470}
1471
1472static void
1473event_free(stonith_event_t * event)
1474{
1475 struct event_private *event_private = event->opaque;
1476
1477 free(event->id);
1478 free(event->operation);
1479 free(event->origin);
1480 free(event->action);
1481 free(event->target);
1482 free(event->executioner);
1483 free(event->device);
1484 free(event->client_origin);
1485 pcmk__reset_result(&event_private->result);
1486 free(event->opaque);
1487 free(event);
1488}
1489
1490static void
1491stonith_send_notification(gpointer data, gpointer user_data)
1492{
1493 struct notify_blob_s *blob = user_data;
1495 stonith_event_t *st_event = NULL;
1496 const char *event = NULL;
1497
1498 if (blob->xml == NULL) {
1499 crm_warn("Skipping callback - NULL message");
1500 return;
1501 }
1502
1503 event = crm_element_value(blob->xml, PCMK__XA_SUBT);
1504
1505 if (entry == NULL) {
1506 crm_warn("Skipping callback - NULL callback client");
1507 return;
1508
1509 } else if (entry->delete) {
1510 crm_trace("Skipping callback - marked for deletion");
1511 return;
1512
1513 } else if (entry->notify == NULL) {
1514 crm_warn("Skipping callback - NULL callback");
1515 return;
1516
1517 } else if (!pcmk__str_eq(entry->event, event, pcmk__str_none)) {
1518 crm_trace("Skipping callback - event mismatch %p/%s vs. %s", entry, entry->event, event);
1519 return;
1520 }
1521
1522 st_event = xml_to_event(blob->xml);
1523
1524 crm_trace("Invoking callback for %p/%s event...", entry, event);
1525 // coverity[null_field]
1526 entry->notify(blob->stonith, st_event);
1527 crm_trace("Callback invoked...");
1528
1529 event_free(st_event);
1530}
1531
1546static int
1547stonith_send_command(stonith_t * stonith, const char *op, xmlNode * data, xmlNode ** output_data,
1548 int call_options, int timeout)
1549{
1550 int rc = 0;
1551 int reply_id = -1;
1552
1553 xmlNode *op_msg = NULL;
1554 xmlNode *op_reply = NULL;
1555 stonith_private_t *native = NULL;
1556
1557 pcmk__assert((stonith != NULL) && (stonith->st_private != NULL)
1558 && (op != NULL));
1559 native = stonith->st_private;
1560
1561 if (output_data != NULL) {
1562 *output_data = NULL;
1563 }
1564
1565 if ((stonith->state == stonith_disconnected) || (native->token == NULL)) {
1566 return -ENOTCONN;
1567 }
1568
1569 /* Increment the call ID, which must be positive to avoid conflicting with
1570 * error codes. This shouldn't be a problem unless the client mucked with
1571 * it or the counter wrapped around.
1572 */
1573 stonith->call_id++;
1574 if (stonith->call_id < 1) {
1575 stonith->call_id = 1;
1576 }
1577
1578 op_msg = stonith_create_op(stonith->call_id, native->token, op, data, call_options);
1579 if (op_msg == NULL) {
1580 return -EINVAL;
1581 }
1582
1584 crm_trace("Sending %s message to fencer with timeout %ds", op, timeout);
1585
1586 if (data) {
1587 const char *delay_s = crm_element_value(data, PCMK__XA_ST_DELAY);
1588
1589 if (delay_s) {
1590 crm_xml_add(op_msg, PCMK__XA_ST_DELAY, delay_s);
1591 }
1592 }
1593
1594 {
1595 enum crm_ipc_flags ipc_flags = crm_ipc_flags_none;
1596
1597 if (call_options & st_opt_sync_call) {
1598 pcmk__set_ipc_flags(ipc_flags, "stonith command",
1600 }
1601 rc = crm_ipc_send(native->ipc, op_msg, ipc_flags,
1602 1000 * (timeout + 60), &op_reply);
1603 }
1604 pcmk__xml_free(op_msg);
1605
1606 if (rc < 0) {
1607 crm_perror(LOG_ERR, "Couldn't perform %s operation (timeout=%ds): %d", op, timeout, rc);
1608 rc = -ECOMM;
1609 goto done;
1610 }
1611
1612 crm_log_xml_trace(op_reply, "Reply");
1613
1614 if (!(call_options & st_opt_sync_call)) {
1615 crm_trace("Async call %d, returning", stonith->call_id);
1616 pcmk__xml_free(op_reply);
1617 return stonith->call_id;
1618 }
1619
1620 crm_element_value_int(op_reply, PCMK__XA_ST_CALLID, &reply_id);
1621
1622 if (reply_id == stonith->call_id) {
1624
1625 crm_trace("Synchronous reply %d received", reply_id);
1626
1627 stonith__xe_get_result(op_reply, &result);
1630
1631 if ((call_options & st_opt_discard_reply) || output_data == NULL) {
1632 crm_trace("Discarding reply");
1633
1634 } else {
1635 *output_data = op_reply;
1636 op_reply = NULL; /* Prevent subsequent free */
1637 }
1638
1639 } else if (reply_id <= 0) {
1640 crm_err("Received bad reply: No id set");
1641 crm_log_xml_err(op_reply, "Bad reply");
1642 pcmk__xml_free(op_reply);
1643 op_reply = NULL;
1644 rc = -ENOMSG;
1645
1646 } else {
1647 crm_err("Received bad reply: %d (wanted %d)", reply_id, stonith->call_id);
1648 crm_log_xml_err(op_reply, "Old reply");
1649 pcmk__xml_free(op_reply);
1650 op_reply = NULL;
1651 rc = -ENOMSG;
1652 }
1653
1654 done:
1655 if (!crm_ipc_connected(native->ipc)) {
1656 crm_err("Fencer disconnected");
1657 free(native->token); native->token = NULL;
1658 stonith->state = stonith_disconnected;
1659 }
1660
1661 pcmk__xml_free(op_reply);
1662 return rc;
1663}
1664
1676int
1678{
1679 stonith_private_t *private = NULL;
1680
1681 pcmk__assert(stonith_api != NULL);
1682 private = stonith_api->st_private;
1683
1684 while (crm_ipc_ready(private->ipc)) {
1685 if (crm_ipc_read(private->ipc) > 0) {
1686 const char *msg = crm_ipc_buffer(private->ipc);
1687
1688 stonith_dispatch_internal(msg, strlen(msg), stonith_api);
1689 pcmk__ipc_free_client_buffer(private->ipc);
1690 }
1691
1692 if (!crm_ipc_connected(private->ipc)) {
1693 crm_err("Connection closed");
1694 return ENOTCONN;
1695 }
1696 }
1697
1698 return pcmk_rc_ok;
1699}
1700
1701static int
1702free_stonith_api(stonith_t *stonith)
1703{
1704 int rc = pcmk_ok;
1705
1706 crm_trace("Destroying %p", stonith);
1707
1708 if (stonith->state != stonith_disconnected) {
1709 crm_trace("Unregistering notifications and disconnecting %p first",
1710 stonith);
1711 stonith->cmds->remove_notification(stonith, NULL);
1712 rc = stonith->cmds->disconnect(stonith);
1713 }
1714
1715 if (stonith->state == stonith_disconnected) {
1716 stonith_private_t *private = stonith->st_private;
1717
1718 crm_trace("Removing %d callbacks", g_hash_table_size(private->stonith_op_callback_table));
1719 g_hash_table_destroy(private->stonith_op_callback_table);
1720
1721 crm_trace("Destroying %d notification clients", g_list_length(private->notify_list));
1722 g_list_free_full(private->notify_list, free);
1723
1724 free(stonith->st_private);
1725 free(stonith->cmds);
1726 free(stonith);
1727
1728 } else {
1729 crm_err("Not free'ing active connection: %s (%d)", pcmk_strerror(rc), rc);
1730 }
1731
1732 return rc;
1733}
1734
1735static gboolean
1736is_stonith_param(gpointer key, gpointer value, gpointer user_data)
1737{
1738 return pcmk_stonith_param(key);
1739}
1740
1741int
1742stonith__validate(stonith_t *st, int call_options, const char *rsc_id,
1743 const char *agent, GHashTable *params, int timeout_sec,
1744 char **output, char **error_output)
1745{
1746 int rc = pcmk_rc_ok;
1747
1748 /* Use a dummy node name in case the agent requires a target. We assume the
1749 * actual target doesn't matter for validation purposes (if in practice,
1750 * that is incorrect, we will need to allow the caller to pass the target).
1751 */
1752 const char *target = "node1";
1753 char *host_arg = NULL;
1754
1755 if (params != NULL) {
1756 host_arg = pcmk__str_copy(g_hash_table_lookup(params, PCMK_STONITH_HOST_ARGUMENT));
1757
1758 /* Remove special stonith params from the table before doing anything else */
1759 g_hash_table_foreach_remove(params, is_stonith_param, NULL);
1760 }
1761
1762#if PCMK__ENABLE_CIBSECRETS
1763 rc = pcmk__substitute_secrets(rsc_id, params);
1764 if (rc != pcmk_rc_ok) {
1765 crm_warn("Could not replace secret parameters for validation of %s: %s",
1766 agent, pcmk_rc_str(rc));
1767 // rc is standard return value, don't return it in this function
1768 }
1769#endif
1770
1771 if (output) {
1772 *output = NULL;
1773 }
1774 if (error_output) {
1775 *error_output = NULL;
1776 }
1777
1778 if (timeout_sec <= 0) {
1779 timeout_sec = PCMK_DEFAULT_ACTION_TIMEOUT_MS;
1780 }
1781
1782 switch (get_namespace_from_agent(agent)) {
1783 case st_namespace_rhcs:
1784 rc = stonith__rhcs_validate(st, call_options, target, agent,
1785 params, host_arg, timeout_sec,
1786 output, error_output);
1787 rc = pcmk_legacy2rc(rc);
1788 break;
1789
1790#if HAVE_STONITH_STONITH_H
1791 case st_namespace_lha:
1792 rc = stonith__lha_validate(st, call_options, target, agent,
1793 params, timeout_sec, output,
1794 error_output);
1795 rc = pcmk_legacy2rc(rc);
1796 break;
1797#endif
1798
1800 errno = ENOENT;
1801 rc = errno;
1802
1803 if (error_output) {
1804 *error_output = crm_strdup_printf("Agent %s not found", agent);
1805 } else {
1806 crm_err("Agent %s not found", agent);
1807 }
1808
1809 break;
1810
1811 default:
1812 errno = EOPNOTSUPP;
1813 rc = errno;
1814
1815 if (error_output) {
1816 *error_output = crm_strdup_printf("Agent %s does not support validation",
1817 agent);
1818 } else {
1819 crm_err("Agent %s does not support validation", agent);
1820 }
1821
1822 break;
1823 }
1824
1825 free(host_arg);
1826 return rc;
1827}
1828
1829static int
1830stonith_api_validate(stonith_t *st, int call_options, const char *rsc_id,
1831 const char *namespace_s, const char *agent,
1832 const stonith_key_value_t *params, int timeout_sec,
1833 char **output, char **error_output)
1834{
1835 /* Validation should be done directly via the agent, so we can get it from
1836 * stonith_admin when the cluster is not running, which is important for
1837 * higher-level tools.
1838 */
1839
1840 int rc = pcmk_ok;
1841
1842 GHashTable *params_table = pcmk__strkey_table(free, free);
1843
1844 // Convert parameter list to a hash table
1845 for (; params; params = params->next) {
1846 if (!pcmk_stonith_param(params->key)) {
1847 pcmk__insert_dup(params_table, params->key, params->value);
1848 }
1849 }
1850
1851 rc = stonith__validate(st, call_options, rsc_id, agent, params_table,
1852 timeout_sec, output, error_output);
1853
1854 g_hash_table_destroy(params_table);
1855 return rc;
1856}
1857
1865stonith_t *
1867{
1868 stonith_t *new_stonith = NULL;
1869 stonith_private_t *private = NULL;
1870
1871 new_stonith = calloc(1, sizeof(stonith_t));
1872 if (new_stonith == NULL) {
1873 return NULL;
1874 }
1875
1876 private = calloc(1, sizeof(stonith_private_t));
1877 if (private == NULL) {
1878 free(new_stonith);
1879 return NULL;
1880 }
1881 new_stonith->st_private = private;
1882
1883 private->stonith_op_callback_table = pcmk__intkey_table(stonith_destroy_op_callback);
1884 private->notify_list = NULL;
1885 private->notify_refcnt = 0;
1886 private->notify_deletes = FALSE;
1887
1888 new_stonith->call_id = 1;
1889 new_stonith->state = stonith_disconnected;
1890
1891 new_stonith->cmds = calloc(1, sizeof(stonith_api_operations_t));
1892 if (new_stonith->cmds == NULL) {
1893 free(new_stonith->st_private);
1894 free(new_stonith);
1895 return NULL;
1896 }
1897
1898 new_stonith->cmds->free = free_stonith_api;
1899 new_stonith->cmds->connect = stonith_api_signon;
1900 new_stonith->cmds->disconnect = stonith_api_signoff;
1901
1902 new_stonith->cmds->list = stonith_api_list;
1903 new_stonith->cmds->monitor = stonith_api_monitor;
1904 new_stonith->cmds->status = stonith_api_status;
1905 new_stonith->cmds->fence = stonith_api_fence;
1906 new_stonith->cmds->fence_with_delay = stonith_api_fence_with_delay;
1907 new_stonith->cmds->confirm = stonith_api_confirm;
1908 new_stonith->cmds->history = stonith_api_history;
1909
1910 new_stonith->cmds->list_agents = stonith_api_device_list;
1911 new_stonith->cmds->metadata = stonith_api_device_metadata;
1912
1913 new_stonith->cmds->query = stonith_api_query;
1914 new_stonith->cmds->remove_device = stonith_api_remove_device;
1915 new_stonith->cmds->register_device = stonith_api_register_device;
1916
1917 new_stonith->cmds->remove_level = stonith_api_remove_level;
1918 new_stonith->cmds->remove_level_full = stonith_api_remove_level_full;
1919 new_stonith->cmds->register_level = stonith_api_register_level;
1920 new_stonith->cmds->register_level_full = stonith_api_register_level_full;
1921
1922 new_stonith->cmds->remove_callback = stonith_api_del_callback;
1923 new_stonith->cmds->register_callback = stonith_api_add_callback;
1924 new_stonith->cmds->remove_notification = stonith_api_del_notification;
1925 new_stonith->cmds->register_notification = stonith_api_add_notification;
1926
1927 new_stonith->cmds->validate = stonith_api_validate;
1928
1929 return new_stonith;
1930}
1931
1938void
1940{
1941 crm_trace("Destroying %p", stonith_api);
1942 if (stonith_api != NULL) {
1943 stonith_api->cmds->free(stonith_api);
1944 }
1945}
1946
1957int
1959 int max_attempts)
1960{
1961 int rc = EINVAL; // if max_attempts is not positive
1962
1963 for (int attempt = 1; attempt <= max_attempts; attempt++) {
1964 rc = stonith_api->cmds->connect(stonith_api, name, NULL);
1965 rc = pcmk_legacy2rc(rc);
1966
1967 if (rc == pcmk_rc_ok) {
1968 return rc;
1969 }
1970 if (attempt < max_attempts) {
1971 crm_notice("Fencer connection attempt %d of %d failed "
1972 "(retrying in 2s): %s " QB_XS " rc=%d",
1973 attempt, max_attempts, pcmk_rc_str(rc), rc);
1974 sleep(2);
1975 }
1976 }
1977 crm_notice("Could not connect to fencer: %s " QB_XS " rc=%d",
1978 pcmk_rc_str(rc), rc);
1979 return rc;
1980}
1981
1996 const char *value)
1997{
1998 /* @COMPAT Replace this function with pcmk_prepend_nvpair(), and reverse the
1999 * list when finished adding to it; or with a hash table where order does
2000 * not matter
2001 */
2003 sizeof(stonith_key_value_t));
2004
2005 pair->key = pcmk__str_copy(key);
2006 pair->value = pcmk__str_copy(value);
2007
2008 if (head != NULL) {
2009 stonith_key_value_t *end = head;
2010
2011 for (; end->next != NULL; end = end->next);
2012 end->next = pair;
2013
2014 } else {
2015 head = pair;
2016 }
2017
2018 return head;
2019}
2020
2032void
2034{
2035 while (head != NULL) {
2036 stonith_key_value_t *next = head->next;
2037
2038 if (keys) {
2039 free(head->key);
2040 }
2041 if (values) {
2042 free(head->value);
2043 }
2044 free(head);
2045 head = next;
2046 }
2047}
2048
2049#define api_log_open() openlog("stonith-api", LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON)
2050#define api_log(level, fmt, args...) syslog(level, "%s: "fmt, __func__, args)
2051
2052int
2053stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off)
2054{
2055 int rc = pcmk_ok;
2057 const char *action = off? PCMK_ACTION_OFF : PCMK_ACTION_REBOOT;
2058
2059 api_log_open();
2060 if (st == NULL) {
2061 api_log(LOG_ERR, "API initialization failed, could not kick (%s) node %u/%s",
2062 action, nodeid, uname);
2063 return -EPROTO;
2064 }
2065
2066 rc = st->cmds->connect(st, "stonith-api", NULL);
2067 if (rc != pcmk_ok) {
2068 api_log(LOG_ERR, "Connection failed, could not kick (%s) node %u/%s : %s (%d)",
2069 action, nodeid, uname, pcmk_strerror(rc), rc);
2070 } else {
2071 char *name = (uname == NULL)? pcmk__itoa(nodeid) : strdup(uname);
2072 int opts = 0;
2073
2076 if ((uname == NULL) && (nodeid > 0)) {
2078 }
2079 rc = st->cmds->fence(st, opts, name, action, timeout, 0);
2080 free(name);
2081
2082 if (rc != pcmk_ok) {
2083 api_log(LOG_ERR, "Could not kick (%s) node %u/%s : %s (%d)",
2084 action, nodeid, uname, pcmk_strerror(rc), rc);
2085 } else {
2086 api_log(LOG_NOTICE, "Node %u/%s kicked: %s", nodeid, uname, action);
2087 }
2088 }
2089
2091 return rc;
2092}
2093
2094time_t
2095stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress)
2096{
2097 int rc = pcmk_ok;
2098 time_t when = 0;
2100 stonith_history_t *history = NULL, *hp = NULL;
2101
2102 if (st == NULL) {
2103 api_log(LOG_ERR, "Could not retrieve fence history for %u/%s: "
2104 "API initialization failed", nodeid, uname);
2105 return when;
2106 }
2107
2108 rc = st->cmds->connect(st, "stonith-api", NULL);
2109 if (rc != pcmk_ok) {
2110 api_log(LOG_NOTICE, "Connection failed: %s (%d)", pcmk_strerror(rc), rc);
2111 } else {
2112 int entries = 0;
2113 int progress = 0;
2114 int completed = 0;
2115 int opts = 0;
2116 char *name = (uname == NULL)? pcmk__itoa(nodeid) : strdup(uname);
2117
2119 if ((uname == NULL) && (nodeid > 0)) {
2121 }
2122 rc = st->cmds->history(st, opts, name, &history, 120);
2123 free(name);
2124
2125 for (hp = history; hp; hp = hp->next) {
2126 entries++;
2127 if (in_progress) {
2128 progress++;
2129 if (hp->state != st_done && hp->state != st_failed) {
2130 when = time(NULL);
2131 }
2132
2133 } else if (hp->state == st_done) {
2134 completed++;
2135 if (hp->completed > when) {
2136 when = hp->completed;
2137 }
2138 }
2139 }
2140
2141 stonith__history_free(history);
2142
2143 if(rc == pcmk_ok) {
2144 api_log(LOG_INFO, "Found %d entries for %u/%s: %d in progress, %d completed", entries, nodeid, uname, progress, completed);
2145 } else {
2146 api_log(LOG_ERR, "Could not retrieve fence history for %u/%s: %s (%d)", nodeid, uname, pcmk_strerror(rc), rc);
2147 }
2148 }
2149
2151
2152 if(when) {
2153 api_log(LOG_INFO, "Node %u/%s last kicked at: %ld", nodeid, uname, (long int)when);
2154 }
2155 return when;
2156}
2157
2167bool
2169{
2170 stonith_t *stonith_api = NULL;
2171 stonith_key_value_t *agents = NULL;
2172 bool rc = false;
2173
2174 if (name == NULL) {
2175 return false;
2176 }
2177
2178 stonith_api = stonith__api_new();
2179 if (stonith_api == NULL) {
2180 crm_err("Could not list fence agents: API memory allocation failed");
2181 return false;
2182 }
2183
2184 // The list_agents method ignores its timeout argument
2185 stonith_api->cmds->list_agents(stonith_api, st_opt_sync_call, NULL, &agents,
2186 0);
2187
2188 for (const stonith_key_value_t *iter = agents; iter != NULL;
2189 iter = iter->next) {
2190 if (pcmk__str_eq(iter->value, name, pcmk__str_none)) {
2191 rc = true;
2192 break;
2193 }
2194 }
2195
2196 stonith__key_value_freeall(agents, true, true);
2197 stonith__api_free(stonith_api);
2198 return rc;
2199}
2200
2209static void
2210parse_list_line(const char *line, int len, GList **output)
2211{
2212 size_t i = 0;
2213 size_t entry_start = 0;
2214
2215 if (line == NULL) {
2216 return;
2217 }
2218
2219 /* Skip complaints about additional parameters device doesn't understand
2220 *
2221 * @TODO Document or eliminate the implied restriction of target names
2222 */
2223 if (strstr(line, "invalid") || strstr(line, "variable")) {
2224 crm_debug("Skipping list output line: %s", line);
2225 return;
2226 }
2227
2228 // Process line content, character by character
2229 for (i = 0; i <= len; i++) {
2230
2231 if (isspace(line[i]) || (line[i] == ',') || (line[i] == ';')
2232 || (line[i] == '\0')) {
2233 // We've found a separator (i.e. the end of an entry)
2234
2235 int rc = 0;
2236 char *entry = NULL;
2237
2238 if (i == entry_start) {
2239 // Skip leading and sequential separators
2240 entry_start = i + 1;
2241 continue;
2242 }
2243
2244 entry = pcmk__assert_alloc(i - entry_start + 1, sizeof(char));
2245
2246 /* Read entry, stopping at first separator
2247 *
2248 * @TODO Document or eliminate these character restrictions
2249 */
2250 rc = sscanf(line + entry_start, "%[a-zA-Z0-9_-.]", entry);
2251 if (rc != 1) {
2252 crm_warn("Could not parse list output entry: %s "
2253 QB_XS " entry_start=%d position=%d",
2254 line + entry_start, entry_start, i);
2255 free(entry);
2256
2257 } else if (pcmk__strcase_any_of(entry, PCMK_ACTION_ON,
2258 PCMK_ACTION_OFF, NULL)) {
2259 /* Some agents print the target status in the list output,
2260 * though none are known now (the separate list-status command
2261 * is used for this, but it can also print "UNKNOWN"). To handle
2262 * this possibility, skip such entries.
2263 *
2264 * @TODO Document or eliminate the implied restriction of target
2265 * names.
2266 */
2267 free(entry);
2268
2269 } else {
2270 // We have a valid entry
2271 *output = g_list_append(*output, entry);
2272 }
2273 entry_start = i + 1;
2274 }
2275 }
2276}
2277
2299GList *
2300stonith__parse_targets(const char *target_spec)
2301{
2302 GList *targets = NULL;
2303
2304 if (target_spec != NULL) {
2305 size_t out_len = strlen(target_spec);
2306 size_t line_start = 0; // Starting index of line being processed
2307
2308 for (size_t i = 0; i <= out_len; ++i) {
2309 if ((target_spec[i] == '\n') || (target_spec[i] == '\0')
2310 || ((target_spec[i] == '\\') && (target_spec[i + 1] == 'n'))) {
2311 // We've reached the end of one line of output
2312
2313 int len = i - line_start;
2314
2315 if (len > 0) {
2316 char *line = strndup(target_spec + line_start, len);
2317
2318 pcmk__assert(line != NULL);
2319
2320 // cppcheck-suppress nullPointerOutOfMemory
2321 line[len] = '\0'; // Because it might be a newline
2322 parse_list_line(line, len, &targets);
2323 free(line);
2324 }
2325 if (target_spec[i] == '\\') {
2326 ++i; // backslash-n takes up two positions
2327 }
2328 line_start = i + 1;
2329 }
2330 }
2331 }
2332 return targets;
2333}
2334
2346const char *
2348 const stonith_history_t *top_history)
2349{
2350 const char *other = NULL;
2351
2352 for (const stonith_history_t *prev_hp = top_history;
2353 prev_hp != NULL; prev_hp = prev_hp->next) {
2354 if (prev_hp == event) {
2355 break;
2356 }
2357 if ((prev_hp->state == st_done) &&
2358 pcmk__str_eq(event->target, prev_hp->target, pcmk__str_casei) &&
2359 pcmk__str_eq(event->action, prev_hp->action, pcmk__str_none) &&
2360 ((event->completed < prev_hp->completed) ||
2361 ((event->completed == prev_hp->completed) && (event->completed_nsec < prev_hp->completed_nsec)))) {
2362
2363 if ((event->delegate == NULL)
2364 || pcmk__str_eq(event->delegate, prev_hp->delegate,
2365 pcmk__str_casei)) {
2366 // Prefer equivalent fencing by same executioner
2367 return prev_hp->delegate;
2368
2369 } else if (other == NULL) {
2370 // Otherwise remember first successful executioner
2371 other = (prev_hp->delegate == NULL)? "some node" : prev_hp->delegate;
2372 }
2373 }
2374 }
2375 return other;
2376}
2377
2388{
2389 stonith_history_t *new = NULL, *pending = NULL, *hp, *np, *tmp;
2390
2391 for (hp = history; hp; ) {
2392 tmp = hp->next;
2393 if ((hp->state == st_done) || (hp->state == st_failed)) {
2394 /* sort into new */
2395 if ((!new) || (hp->completed > new->completed) ||
2396 ((hp->completed == new->completed) && (hp->completed_nsec > new->completed_nsec))) {
2397 hp->next = new;
2398 new = hp;
2399 } else {
2400 np = new;
2401 do {
2402 if ((!np->next) || (hp->completed > np->next->completed) ||
2403 ((hp->completed == np->next->completed) && (hp->completed_nsec > np->next->completed_nsec))) {
2404 hp->next = np->next;
2405 np->next = hp;
2406 break;
2407 }
2408 np = np->next;
2409 } while (1);
2410 }
2411 } else {
2412 /* put into pending */
2413 hp->next = pending;
2414 pending = hp;
2415 }
2416 hp = tmp;
2417 }
2418
2419 /* pending actions don't have a completed-stamp so make them go front */
2420 if (pending) {
2421 stonith_history_t *last_pending = pending;
2422
2423 while (last_pending->next) {
2424 last_pending = last_pending->next;
2425 }
2426
2427 last_pending->next = new;
2428 new = pending;
2429 }
2430 return new;
2431}
2432
2441const char *
2443{
2444 // @COMPAT Move this to the fencer after dropping stonith_op_state_str()
2445 switch (state) {
2446 case st_query:
2447 return "querying";
2448 case st_exec:
2449 return "executing";
2450 case st_done:
2451 return "completed";
2452 case st_duplicate:
2453 return "duplicate";
2454 case st_failed:
2455 return "failed";
2456 default:
2457 return "unknown";
2458 }
2459}
2460
2463 bool (*matching_fn)(stonith_history_t *, void *),
2464 void *user_data)
2465{
2466 for (stonith_history_t *hp = history; hp; hp = hp->next) {
2467 if (matching_fn(hp, user_data)) {
2468 return hp;
2469 }
2470 }
2471
2472 return NULL;
2473}
2474
2475bool
2477{
2478 return history->state != st_failed && history->state != st_done;
2479}
2480
2481bool
2483{
2484 return history->state == GPOINTER_TO_INT(user_data);
2485}
2486
2487bool
2489{
2490 return history->state != GPOINTER_TO_INT(user_data);
2491}
2492
2503static bool
2504param_is_supported(xmlNode *metadata, const char *name)
2505{
2506 char *xpath_s = crm_strdup_printf("//" PCMK_XE_PARAMETER
2507 "[@" PCMK_XA_NAME "='%s']",
2508 name);
2509 xmlXPathObject *xpath = pcmk__xpath_search(metadata->doc, xpath_s);
2510 bool supported = (pcmk__xpath_num_results(xpath) > 0);
2511
2512 free(xpath_s);
2513 xmlXPathFreeObject(xpath);
2514 return supported;
2515}
2516
2528const char *
2530{
2531 CRM_CHECK(metadata != NULL, return NULL);
2532
2533 if (param_is_supported(metadata, "plug")) {
2534 return "plug";
2535 }
2536 if (param_is_supported(metadata, "port")) {
2537 return "port";
2538 }
2539 return NULL;
2540}
2541
2561int
2562stonith__metadata_async(const char *agent, int timeout_sec,
2563 void (*callback)(int pid,
2565 void *user_data),
2566 void *user_data)
2567{
2568 switch (get_namespace_from_agent(agent)) {
2569 case st_namespace_rhcs:
2570 {
2571 stonith_action_t *action = NULL;
2572 int rc = pcmk_ok;
2573
2575 NULL, timeout_sec, NULL, NULL,
2576 NULL);
2577
2578 rc = stonith__execute_async(action, user_data, callback, NULL);
2579 if (rc != pcmk_ok) {
2580 callback(0, stonith__action_result(action), user_data);
2582 }
2583 return pcmk_legacy2rc(rc);
2584 }
2585
2586#if HAVE_STONITH_STONITH_H
2587 case st_namespace_lha:
2588 // LHA metadata is simply synthesized, so simulate async
2589 {
2591 .exit_status = CRM_EX_OK,
2592 .execution_status = PCMK_EXEC_DONE,
2593 .exit_reason = NULL,
2594 .action_stdout = NULL,
2595 .action_stderr = NULL,
2596 };
2597
2598 stonith__lha_metadata(agent, timeout_sec,
2600 callback(0, &result, user_data);
2602 return pcmk_rc_ok;
2603 }
2604#endif
2605
2606 default:
2607 {
2609 .exit_status = CRM_EX_NOSUCH,
2610 .execution_status = PCMK_EXEC_ERROR_HARD,
2611 .exit_reason = crm_strdup_printf("No such agent '%s'",
2612 agent),
2613 .action_stdout = NULL,
2614 .action_stderr = NULL,
2615 };
2616
2617 callback(0, &result, user_data);
2619 return ENOENT;
2620 }
2621 }
2622}
2623
2632int
2634{
2635 if ((data == NULL) || (data->opaque == NULL)) {
2636 return CRM_EX_ERROR;
2637 }
2638 return ((pcmk__action_result_t *) data->opaque)->exit_status;
2639}
2640
2649int
2651{
2652 if ((data == NULL) || (data->opaque == NULL)) {
2653 return PCMK_EXEC_UNKNOWN;
2654 }
2655 return ((pcmk__action_result_t *) data->opaque)->execution_status;
2656}
2657
2666const char *
2668{
2669 if ((data == NULL) || (data->opaque == NULL)) {
2670 return NULL;
2671 }
2672 return ((pcmk__action_result_t *) data->opaque)->exit_reason;
2673}
2674
2683int
2685{
2686 if ((event == NULL) || (event->opaque == NULL)) {
2687 return CRM_EX_ERROR;
2688 } else {
2689 struct event_private *event_private = event->opaque;
2690
2691 return event_private->result.exit_status;
2692 }
2693}
2694
2703int
2705{
2706 if ((event == NULL) || (event->opaque == NULL)) {
2707 return PCMK_EXEC_UNKNOWN;
2708 } else {
2709 struct event_private *event_private = event->opaque;
2710
2711 return event_private->result.execution_status;
2712 }
2713}
2714
2723const char *
2725{
2726 if ((event == NULL) || (event->opaque == NULL)) {
2727 return NULL;
2728 } else {
2729 struct event_private *event_private = event->opaque;
2730
2731 return event_private->result.exit_reason;
2732 }
2733}
2734
2745char *
2747{
2748 // Use somewhat readable defaults
2749 const char *origin = pcmk__s(event->client_origin, "a client");
2750 const char *origin_node = pcmk__s(event->origin, "a node");
2751 const char *executioner = pcmk__s(event->executioner, "the cluster");
2752 const char *device = pcmk__s(event->device, "unknown");
2753 const char *action = pcmk__s(event->action, event->operation);
2754 const char *target = pcmk__s(event->target, "no node");
2755 const char *reason = stonith__event_exit_reason(event);
2756 const char *status;
2757
2758 if (action == NULL) {
2759 action = "(unknown)";
2760 }
2761
2763 status = pcmk_exec_status_str(stonith__event_execution_status(event));
2764 } else if (stonith__event_exit_status(event) != CRM_EX_OK) {
2765 status = pcmk_exec_status_str(PCMK_EXEC_ERROR);
2766 } else {
2767 status = crm_exit_str(CRM_EX_OK);
2768 }
2769
2770 if (pcmk__str_eq(event->operation, PCMK__VALUE_ST_NOTIFY_HISTORY,
2771 pcmk__str_none)) {
2772 return crm_strdup_printf("Fencing history may have changed");
2773
2774 } else if (pcmk__str_eq(event->operation, STONITH_OP_DEVICE_ADD,
2775 pcmk__str_none)) {
2776 return crm_strdup_printf("A fencing device (%s) was added", device);
2777
2778 } else if (pcmk__str_eq(event->operation, STONITH_OP_DEVICE_DEL,
2779 pcmk__str_none)) {
2780 return crm_strdup_printf("A fencing device (%s) was removed", device);
2781
2782 } else if (pcmk__str_eq(event->operation, STONITH_OP_LEVEL_ADD,
2783 pcmk__str_none)) {
2784 return crm_strdup_printf("A fencing topology level (%s) was added",
2785 device);
2786
2787 } else if (pcmk__str_eq(event->operation, STONITH_OP_LEVEL_DEL,
2788 pcmk__str_none)) {
2789 return crm_strdup_printf("A fencing topology level (%s) was removed",
2790 device);
2791 }
2792
2793 // event->operation should be PCMK__VALUE_ST_NOTIFY_FENCE at this point
2794
2795 return crm_strdup_printf("Operation %s of %s by %s for %s@%s: %s%s%s%s (ref=%s)",
2796 action, target, executioner, origin, origin_node,
2797 status,
2798 ((reason == NULL)? "" : " ("), pcmk__s(reason, ""),
2799 ((reason == NULL)? "" : ")"),
2800 pcmk__s(event->id, "(none)"));
2801}
2802
2803// Deprecated functions kept only for backward API compatibility
2804// LCOV_EXCL_START
2805
2806// See comments in stonith-ng.h for why we re-declare before defining
2807
2809
2810stonith_t *
2812{
2813 return stonith__api_new();
2814}
2815
2816void stonith_api_delete(stonith_t *stonith);
2817
2818void
2820{
2821 stonith__api_free(stonith);
2822}
2823
2824static void
2825stonith_dump_pending_op(gpointer key, gpointer value, gpointer user_data)
2826{
2827 int call = GPOINTER_TO_INT(key);
2828 stonith_callback_client_t *blob = value;
2829
2830 crm_debug("Call %d (%s): pending", call, pcmk__s(blob->id, "no ID"));
2831}
2832
2834
2835void
2837{
2838 stonith_private_t *private = stonith->st_private;
2839
2840 if (private->stonith_op_callback_table == NULL) {
2841 return;
2842 }
2843 return g_hash_table_foreach(private->stonith_op_callback_table,
2844 stonith_dump_pending_op, NULL);
2845}
2846
2847bool stonith_dispatch(stonith_t *stonith_api);
2848
2849bool
2851{
2852 return (stonith__api_dispatch(stonith_api) == pcmk_rc_ok);
2853}
2854
2856 const char *key, const char *value);
2857
2860 const char *value)
2861{
2862 return stonith__key_value_add(head, key, value);
2863}
2864
2865void stonith_key_value_freeall(stonith_key_value_t *head, int keys, int values);
2866
2867void
2869{
2870 stonith__key_value_freeall(head, (keys != 0), (values != 0));
2871}
2872
2874
2875void
2880
2881int stonith_api_connect_retry(stonith_t *st, const char *name,
2882 int max_attempts);
2883
2884int
2885stonith_api_connect_retry(stonith_t *st, const char *name, int max_attempts)
2886{
2887 return pcmk_rc2legacy(stonith__api_connect_retry(st, name, max_attempts));
2888}
2889
2890const char *stonith_op_state_str(enum op_state state);
2891
2892const char *
2894{
2895 return stonith__op_state_text(state);
2896}
2897
2898bool stonith_agent_exists(const char *agent, int timeout);
2899
2900bool
2901stonith_agent_exists(const char *agent, int timeout)
2902{
2903 return stonith__agent_exists(agent);
2904}
2905
2906const char *stonith_action_str(const char *action);
2907
2908const char *
2910{
2911 if (action == NULL) {
2912 return "fencing";
2913 } else if (strcmp(action, PCMK_ACTION_ON) == 0) {
2914 return "unfencing";
2915 } else if (strcmp(action, PCMK_ACTION_OFF) == 0) {
2916 return "turning off";
2917 } else {
2918 return action;
2919 }
2920}
2921
2922enum stonith_namespace stonith_text2namespace(const char *namespace_s);
2923
2925stonith_text2namespace(const char *namespace_s)
2926{
2927 return parse_namespace(namespace_s);
2928}
2929
2930const char *stonith_namespace2text(enum stonith_namespace st_namespace);
2931
2932const char *
2934{
2935 return namespace_text(st_namespace);
2936}
2937
2938enum stonith_namespace stonith_get_namespace(const char *agent,
2939 const char *namespace_s);
2940
2942stonith_get_namespace(const char *agent, const char *namespace_s)
2943{
2944 if (pcmk__str_eq(namespace_s, "internal", pcmk__str_none)) {
2945 return st_namespace_internal;
2946 }
2947 return get_namespace_from_agent(agent);
2948}
2949
2950// LCOV_EXCL_STOP
2951// End deprecated API
#define PCMK_ACTION_STATUS
Definition actions.h:64
#define PCMK_ACTION_LIST
Definition actions.h:43
#define PCMK_ACTION_REBOOT
Definition actions.h:59
#define PCMK_ACTION_METADATA
Definition actions.h:48
#define PCMK_DEFAULT_ACTION_TIMEOUT_MS
Default timeout (in milliseconds) for non-metadata actions.
Definition actions.h:33
#define PCMK_ACTION_MONITOR
Definition actions.h:51
#define PCMK_ACTION_ON
Definition actions.h:55
#define PCMK_ACTION_OFF
Definition actions.h:54
#define PCMK_STONITH_HOST_ARGUMENT
Definition agents.h:40
bool pcmk_stonith_param(const char *param)
Check whether a given stonith parameter is handled by Pacemaker.
Definition agents.c:166
const char * name
Definition cib.c:26
int pcmk__substitute_secrets(const char *rsc_id, GHashTable *params)
guint pcmk__create_timer(guint interval_ms, GSourceFunc fn, gpointer data)
Definition utils.c:405
#define pcmk__assert_alloc(nmemb, size)
Definition internal.h:246
char uname[MAX_NAME]
Definition cpg.c:5
char data[0]
Definition cpg.c:10
uint32_t pid
Definition cpg.c:1
enum pcmk_ipc_server type
Definition cpg.c:3
A dumping ground.
#define CRM_OP_REGISTER
Definition crm.h:122
int stonith__legacy2status(int rc)
Definition st_actions.c:390
int stonith__execute_async(stonith_action_t *action, void *userdata, void(*done)(int pid, const pcmk__action_result_t *result, void *user_data), void(*fork_cb)(int pid, void *user_data))
Definition st_actions.c:679
#define STONITH_OP_QUERY
Definition internal.h:115
#define STONITH_OP_FENCE
Definition internal.h:116
void stonith__destroy_action(stonith_action_t *action)
Definition st_actions.c:206
#define STONITH_OP_DEVICE_ADD
Definition internal.h:118
#define STONITH_OP_EXEC
Definition internal.h:113
#define STONITH_WATCHDOG_ID
Definition internal.h:130
#define STONITH_OP_LEVEL_ADD
Definition internal.h:121
#define STONITH_OP_FENCE_HISTORY
Definition internal.h:120
#define STONITH_OP_NOTIFY
Definition internal.h:123
pcmk__action_result_t * stonith__action_result(stonith_action_t *action)
Definition st_actions.c:231
struct stonith_action_s stonith_action_t
Definition internal.h:55
#define stonith__set_call_options(st_call_opts, call_for, flags_to_set)
Definition internal.h:40
void stonith__xe_get_result(const xmlNode *xml, pcmk__action_result_t *result)
Definition st_actions.c:483
#define STONITH_OP_LEVEL_DEL
Definition internal.h:122
int stonith__result2rc(const pcmk__action_result_t *result)
Definition st_actions.c:316
#define STONITH_OP_DEVICE_DEL
Definition internal.h:119
stonith_action_t * stonith__action_create(const char *agent, const char *action_name, const char *target, int timeout_sec, GHashTable *device_args, GHashTable *port_map, const char *host_arg)
Definition st_actions.c:253
G_GNUC_INTERNAL bool stonith__agent_is_rhcs(const char *agent)
Definition st_rhcs.c:257
G_GNUC_INTERNAL int stonith__rhcs_validate(stonith_t *st, int call_options, const char *target, const char *agent, GHashTable *params, const char *host_arg, int timeout, char **output, char **error_output)
Definition st_rhcs.c:268
G_GNUC_INTERNAL int stonith__list_rhcs_agents(stonith_key_value_t **devices)
Definition st_rhcs.c:69
G_GNUC_INTERNAL int stonith__rhcs_metadata(const char *agent, int timeout, char **output)
Retrieve metadata for RHCS-compatible fence agent.
Definition st_rhcs.c:225
void crm_ipc_destroy(crm_ipc_t *client)
Definition ipc_client.c:976
int crm_ipc_send(crm_ipc_t *client, const xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Send an IPC XML message.
long crm_ipc_read(crm_ipc_t *client)
crm_ipc_flags
Definition ipc.h:135
@ crm_ipc_flags_none
Definition ipc.h:136
@ crm_ipc_client_response
A response is expected in reply.
Definition ipc.h:142
int crm_ipc_ready(crm_ipc_t *client)
Check whether an IPC connection is ready to be read.
bool crm_ipc_connected(crm_ipc_t *client)
void crm_ipc_close(crm_ipc_t *client)
Definition ipc_client.c:963
const char * crm_ipc_buffer(crm_ipc_t *client)
struct crm_ipc_s crm_ipc_t
Definition ipc.h:159
crm_ipc_t * crm_ipc_new(const char *name, size_t max_size)
Create a new (legacy) object for using Pacemaker daemon IPC.
Definition ipc_client.c:877
int pcmk__connect_generic_ipc(crm_ipc_t *ipc)
Definition ipc_client.c:912
int pcmk__ipc_fd(crm_ipc_t *ipc, int *fd)
#define pcmk__set_ipc_flags(ipc_flags, ipc_name, flags_to_set)
void pcmk__ipc_free_client_buffer(crm_ipc_t *client)
#define CRM_TRACE_INIT_DATA(name)
Definition logging.h:111
#define crm_info(fmt, args...)
Definition logging.h:365
#define crm_warn(fmt, args...)
Definition logging.h:360
#define crm_log_xml_debug(xml, text)
Definition logging.h:377
#define CRM_LOG_ASSERT(expr)
Definition logging.h:196
#define crm_log_xml_err(xml, text)
Definition logging.h:373
#define crm_notice(fmt, args...)
Definition logging.h:363
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition logging.h:299
#define CRM_CHECK(expr, failure_action)
Definition logging.h:213
#define crm_debug(fmt, args...)
Definition logging.h:368
#define crm_err(fmt, args...)
Definition logging.h:357
#define LOG_NEVER
Definition logging.h:48
#define crm_log_xml_trace(xml, text)
Definition logging.h:378
#define crm_log_xml_warn(xml, text)
Definition logging.h:374
#define crm_trace(fmt, args...)
Definition logging.h:370
#define crm_log_xml_notice(xml, text)
Definition logging.h:375
Wrappers for and extensions to glib mainloop.
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
Definition mainloop.c:953
mainloop_io_t * mainloop_add_ipc_client(const char *name, int priority, size_t max_size, void *userdata, struct ipc_client_callbacks *callbacks)
Definition mainloop.c:922
struct mainloop_io_s mainloop_io_t
Definition mainloop.h:41
#define G_PRIORITY_MEDIUM
Definition mainloop.h:195
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition mainloop.c:947
void hash2field(gpointer key, gpointer value, gpointer user_data)
Set XML attribute based on hash table entry.
Definition nvpair.c:238
#define PCMK__VALUE_ST_NOTIFY_FENCE
#define PCMK__VALUE_ST_NOTIFY
#define PCMK__VALUE_ST_NOTIFY_DISCONNECT
#define PCMK__VALUE_STONITH_NG
#define PCMK__VALUE_ST_NOTIFY_HISTORY
#define PCMK__VALUE_ST_ASYNC_TIMEOUT_VALUE
unsigned int timeout
Definition pcmk_fence.c:34
int delay
Definition pcmk_fence.c:36
unsigned int tolerance
Definition pcmk_fence.c:35
stonith_t * st
Definition pcmk_fence.c:30
const char * action
Definition pcmk_fence.c:32
pcmk__action_result_t result
Definition pcmk_fence.c:37
const char * target
Definition pcmk_fence.c:31
#define ECOMM
Definition portability.h:41
#define ENOTUNIQ
Definition portability.h:36
const char * pcmk_strerror(int rc)
Definition results.c:257
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition results.c:617
@ CRM_EX_NOSUCH
Requested item does not exist.
Definition results.h:269
@ CRM_EX_ERROR
Unspecified error.
Definition results.h:234
@ CRM_EX_OK
Success.
Definition results.h:233
@ pcmk_rc_ok
Definition results.h:159
#define pcmk_ok
Definition results.h:65
int pcmk_rc2legacy(int rc)
Definition results.c:662
const char * crm_exit_str(crm_exit_t exit_code)
Definition results.c:757
@ PCMK_EXEC_DONE
Action completed, result is known.
Definition results.h:311
@ PCMK_EXEC_ERROR
Execution failed, may be retried.
Definition results.h:315
@ PCMK_EXEC_TIMEOUT
Action did not complete in time.
Definition results.h:313
@ PCMK_EXEC_UNKNOWN
Used only to initialize variables.
Definition results.h:309
@ PCMK_EXEC_ERROR_HARD
Execution failed, do not retry on node.
Definition results.h:316
int pcmk_legacy2rc(int legacy_rc)
Definition results.c:675
void pcmk__set_result(pcmk__action_result_t *result, int exit_status, enum pcmk_exec_status exec_status, const char *exit_reason)
Definition results.c:1088
#define pcmk__assert(expr)
#define PCMK__UNKNOWN_RESULT
void pcmk__reset_result(pcmk__action_result_t *result)
Definition results.c:1177
int stonith__metadata_async(const char *agent, int timeout_sec, void(*callback)(int pid, const pcmk__action_result_t *result, void *user_data), void *user_data)
Definition st_client.c:2562
void stonith_api_delete(stonith_t *stonith)
Definition st_client.c:2819
const char * stonith__default_host_arg(xmlNode *metadata)
Definition st_client.c:2529
gboolean stonith__watchdog_fencing_enabled_for_node(const char *node)
Definition st_client.c:241
const char * stonith__exit_reason(const stonith_callback_data_t *data)
Definition st_client.c:2667
const char * stonith_namespace2text(enum stonith_namespace st_namespace)
Definition st_client.c:2933
time_t stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress)
Definition st_client.c:2095
char * stonith__event_description(const stonith_event_t *event)
Definition st_client.c:2746
stonith_key_value_t * stonith_key_value_add(stonith_key_value_t *head, const char *key, const char *value)
Definition st_client.c:2859
bool stonith__event_state_pending(stonith_history_t *history, void *user_data)
Definition st_client.c:2476
GList * stonith__parse_targets(const char *target_spec)
Definition st_client.c:2300
enum stonith_namespace stonith_get_namespace(const char *agent, const char *namespace_s)
Definition st_client.c:2942
xmlNode * stonith_create_op(int call_id, const char *token, const char *op, xmlNode *data, int call_options)
Definition st_client.c:829
bool stonith__event_state_neq(stonith_history_t *history, void *user_data)
Definition st_client.c:2488
enum stonith_namespace stonith_text2namespace(const char *namespace_s)
Definition st_client.c:2925
bool stonith__event_state_eq(stonith_history_t *history, void *user_data)
Definition st_client.c:2482
void stonith_history_free(stonith_history_t *head)
Definition st_client.c:2876
xmlNode * create_device_registration_xml(const char *id, enum stonith_namespace standard, const char *agent, const stonith_key_value_t *params, const char *rsc_provides)
Definition st_client.c:303
const char * stonith_action_str(const char *action)
Definition st_client.c:2909
xmlNode * create_level_registration_xml(const char *node, const char *pattern, const char *attr, const char *value, int level, const stonith_key_value_t *device_list)
Definition st_client.c:425
void stonith__api_free(stonith_t *stonith_api)
Definition st_client.c:1939
struct stonith_private_s stonith_private_t
int stonith_api_connect_retry(stonith_t *st, const char *name, int max_attempts)
Definition st_client.c:2885
stonith_history_t * stonith__first_matching_event(stonith_history_t *history, bool(*matching_fn)(stonith_history_t *, void *), void *user_data)
Definition st_client.c:2462
#define api_log(level, fmt, args...)
Definition st_client.c:2050
int stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off)
Definition st_client.c:2053
int stonith__exit_status(const stonith_callback_data_t *data)
Definition st_client.c:2633
stonith_key_value_t * stonith__key_value_add(stonith_key_value_t *head, const char *key, const char *value)
Definition st_client.c:1995
int stonith__api_connect_retry(stonith_t *stonith_api, const char *name, int max_attempts)
Definition st_client.c:1958
bool stonith__agent_exists(const char *name)
Definition st_client.c:2168
stonith_history_t * stonith__sort_history(stonith_history_t *history)
Definition st_client.c:2387
gboolean stonith__watchdog_fencing_enabled_for_node_api(stonith_t *st, const char *node)
Definition st_client.c:182
int stonith__validate(stonith_t *st, int call_options, const char *rsc_id, const char *agent, GHashTable *params, int timeout_sec, char **output, char **error_output)
Definition st_client.c:1742
int stonith__execution_status(const stonith_callback_data_t *data)
Definition st_client.c:2650
int stonith__api_dispatch(stonith_t *stonith_api)
Definition st_client.c:1677
void stonith__key_value_freeall(stonith_key_value_t *head, bool keys, bool values)
Definition st_client.c:2033
int(* stonith_op_t)(const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **)
Definition st_client.c:85
bool stonith_dispatch(stonith_t *stonith_api)
Definition st_client.c:2850
int stonith__event_exit_status(const stonith_event_t *event)
Definition st_client.c:2684
const char * stonith__op_state_text(enum op_state state)
Definition st_client.c:2442
void stonith__history_free(stonith_history_t *head)
Definition st_client.c:776
int stonith__event_execution_status(const stonith_event_t *event)
Definition st_client.c:2704
stonith_t * stonith_api_new(void)
Definition st_client.c:2811
#define api_log_open()
Definition st_client.c:2049
const char * stonith__later_succeeded(const stonith_history_t *event, const stonith_history_t *top_history)
Definition st_client.c:2347
const char * stonith__event_exit_reason(const stonith_event_t *event)
Definition st_client.c:2724
struct stonith_notify_client_s stonith_notify_client_t
stonith_t * stonith__api_new(void)
Definition st_client.c:1866
void stonith_key_value_freeall(stonith_key_value_t *head, int keys, int values)
Definition st_client.c:2868
struct stonith_callback_client_s stonith_callback_client_t
bool stonith_agent_exists(const char *agent, int timeout)
Definition st_client.c:2901
void stonith_dump_pending_callbacks(stonith_t *stonith)
Definition st_client.c:2836
const char * stonith_op_state_str(enum op_state state)
Definition st_client.c:2893
int stonith__lha_metadata(const char *agent, int timeout, char **output)
Definition st_lha.c:179
int stonith__list_lha_agents(stonith_key_value_t **devices)
Definition st_lha.c:119
int stonith__lha_validate(stonith_t *st, int call_options, const char *target, const char *agent, GHashTable *params, int timeout, char **output, char **error_output)
Definition st_lha.c:302
bool stonith__agent_is_lha(const char *agent)
Definition st_lha.c:92
Fencing aka. STONITH.
@ st_opt_timeout_updates
Definition stonith-ng.h:104
@ st_opt_cs_nodeid
Definition stonith-ng.h:96
@ st_opt_allow_self_fencing
Definition stonith-ng.h:68
@ st_opt_discard_reply
Definition stonith-ng.h:82
@ st_opt_manual_ack
Definition stonith-ng.h:78
@ st_opt_report_only_success
Definition stonith-ng.h:108
@ st_opt_sync_call
Definition stonith-ng.h:100
stonith_namespace
Supported fence agent interface standards.
Definition stonith-ng.h:138
@ st_namespace_invalid
Definition stonith-ng.h:139
@ st_namespace_rhcs
Definition stonith-ng.h:149
@ st_namespace_internal
Definition stonith-ng.h:143
@ st_namespace_any
Definition stonith-ng.h:140
@ st_namespace_lha
Definition stonith-ng.h:152
@ stonith_disconnected
Definition stonith-ng.h:47
@ stonith_connected_command
Definition stonith-ng.h:45
op_state
Fencing operation states.
Definition stonith-ng.h:125
@ st_duplicate
Definition stonith-ng.h:129
@ st_query
Definition stonith-ng.h:126
@ st_failed
Definition stonith-ng.h:130
@ st_done
Definition stonith-ng.h:128
@ st_exec
Definition stonith-ng.h:127
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
void pcmk__insert_dup(GHashTable *table, const char *name, const char *value)
Definition strings.c:703
gboolean pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
Definition strings.c:984
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition strings.c:685
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:1029
@ pcmk__str_none
@ pcmk__str_null_matches
@ pcmk__str_casei
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:1053
#define pcmk__str_copy(str)
void pcmk__add_separated_word(GString **list, size_t init_size, const char *word, const char *separator)
Definition strings.c:796
enum pcmk_exec_status execution_status
Fencer API operations.
Definition stonith-ng.h:230
int(* fence_with_delay)(stonith_t *stonith, int call_options, const char *node, const char *action, int timeout, int tolerance, int delay)
Request delayed fencing of a target.
Definition stonith-ng.h:646
int(* register_level)(stonith_t *st, int options, const char *node, int level, const stonith_key_value_t *device_list)
Register a fencing level for specified node with local fencer.
Definition stonith-ng.h:326
int(* free)(stonith_t *st)
Destroy a fencer connection.
Definition stonith-ng.h:237
int(* register_callback)(stonith_t *stonith, int call_id, int timeout, int options, void *user_data, const char *callback_name, void(*callback)(stonith_t *st, stonith_callback_data_t *data))
Register a callback for an asynchronous fencing result.
Definition stonith-ng.h:528
int(* query)(stonith_t *stonith, int call_options, const char *target, stonith_key_value_t **devices, int timeout)
List registered fence devices.
Definition stonith-ng.h:432
int(* register_notification)(stonith_t *stonith, const char *event, void(*callback)(stonith_t *st, stonith_event_t *e))
Register a callback for fence notifications.
Definition stonith-ng.h:495
int(* connect)(stonith_t *st, const char *name, int *stonith_fd)
Connect to the local fencer.
Definition stonith-ng.h:250
int(* register_device)(stonith_t *st, int options, const char *id, const char *namespace_s, const char *agent, const stonith_key_value_t *params)
Register a fence device with the local fencer.
Definition stonith-ng.h:292
int(* remove_level)(stonith_t *st, int options, const char *node, int level)
Unregister a fencing level for specified node with local fencer.
Definition stonith-ng.h:309
int(* disconnect)(stonith_t *st)
Disconnect from the local stonith daemon.
Definition stonith-ng.h:260
int(* list)(stonith_t *stonith, int call_options, const char *id, char **list_info, int timeout)
Get the output of a fence device's list action.
Definition stonith-ng.h:382
int(* remove_callback)(stonith_t *stonith, int call_id, bool all_callbacks)
Unregister callbacks for asynchronous fencing results.
Definition stonith-ng.h:546
int(* remove_level_full)(stonith_t *st, int options, const char *node, const char *pattern, const char *attr, const char *value, int level)
Unregister fencing level for specified node, pattern or attribute.
Definition stonith-ng.h:570
int(* fence)(stonith_t *stonith, int call_options, const char *node, const char *action, int timeout, int tolerance)
Request that a target get fenced.
Definition stonith-ng.h:454
int(* list_agents)(stonith_t *stonith, int call_options, const char *namespace_s, stonith_key_value_t **devices, int timeout)
Retrieve a list of installed fence agents.
Definition stonith-ng.h:365
int(* confirm)(stonith_t *stonith, int call_options, const char *target)
Manually confirm that a node has been fenced.
Definition stonith-ng.h:468
int(* status)(stonith_t *stonith, int call_options, const char *id, const char *port, int timeout)
Check whether a fence device target is reachable by status action.
Definition stonith-ng.h:414
int(* register_level_full)(stonith_t *st, int options, const char *node, const char *pattern, const char *attr, const char *value, int level, const stonith_key_value_t *device_list)
Register fencing level for specified node, pattern or attribute.
Definition stonith-ng.h:598
int(* validate)(stonith_t *st, int call_options, const char *rsc_id, const char *namespace_s, const char *agent, const stonith_key_value_t *params, int timeout, char **output, char **error_output)
Validate an arbitrary stonith device configuration.
Definition stonith-ng.h:622
int(* monitor)(stonith_t *stonith, int call_options, const char *id, int timeout)
Check whether a fence device is reachable by monitor action.
Definition stonith-ng.h:397
int(* remove_notification)(stonith_t *stonith, const char *event)
Unregister callbacks for fence notifications.
Definition stonith-ng.h:508
int(* remove_device)(stonith_t *st, int options, const char *name)
Unregister a fence device with the local fencer.
Definition stonith-ng.h:273
int(* history)(stonith_t *stonith, int call_options, const char *node, stonith_history_t **history, int timeout)
List fencing actions that have occurred for a target.
Definition stonith-ng.h:482
int(* metadata)(stonith_t *stonith, int call_options, const char *agent, const char *namespace_s, char **output, int timeout_sec)
Retrieve a fence agent's metadata.
Definition stonith-ng.h:344
Data for an asynchronous fencing request callback.
Definition stonith-ng.h:216
Fencing event.
Definition stonith-ng.h:194
char * client_origin
Definition stonith-ng.h:206
Fencing history entry.
Definition stonith-ng.h:173
struct stonith_history_s * next
Definition stonith-ng.h:181
Key-value pair list node.
Definition stonith-ng.h:162
struct stonith_key_value_s * next
Definition stonith-ng.h:165
Fencer API connection object.
Definition stonith-ng.h:657
enum stonith_state state
Definition stonith-ng.h:658
void * st_private
Definition stonith-ng.h:660
stonith_api_operations_t * cmds
Definition stonith-ng.h:661
guint ref
Definition internal.h:119
stonith_t * stonith
Definition st_client.c:82
Wrappers for and extensions to libxml2.
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
int crm_element_value_ll(const xmlNode *data, const char *name, long long *dest)
Retrieve the long long integer value of an XML attribute.
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition xml_element.c:43
xmlNode * pcmk__xe_next(const xmlNode *node, const char *element_name)
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition xml.c:832
void pcmk__xml_free(xmlNode *xml)
Definition xml.c:816
xmlNode * pcmk__xml_parse(const char *input)
Definition xml_io.c:167
#define PCMK_XA_TARGET_PATTERN
Definition xml_names.h:421
#define PCMK_XE_FENCING_LEVEL
Definition xml_names.h:117
#define PCMK_XA_AGENT
Definition xml_names.h:234
#define PCMK_XA_TARGET
Definition xml_names.h:418
#define PCMK_XA_ID
Definition xml_names.h:301
#define PCMK_XA_TARGET_VALUE
Definition xml_names.h:423
#define PCMK_XA_EXIT_REASON
Definition xml_names.h:274
#define PCMK_XA_TARGET_ATTRIBUTE
Definition xml_names.h:419
#define PCMK_XA_NAME
Definition xml_names.h:330
#define PCMK_XE_PARAMETER
Definition xml_names.h:158
#define PCMK_XA_INDEX
Definition xml_names.h:305
#define PCMK_XA_DEVICES
Definition xml_names.h:264
#define PCMK__XA_ST_DATE
#define PCMK__XA_ST_CLIENTID
#define PCMK__XA_NAMESPACE
#define PCMK__XE_ST_CALLDATA
#define PCMK__XA_ST_TARGET
#define PCMK__XA_ST_CALLOPT
#define PCMK__XA_ST_DATE_NSEC
#define PCMK__XA_ST_CALLID
#define PCMK__XA_ST_STATE
#define PCMK__XA_ST_DELEGATE
#define PCMK__XE_NOTIFY
#define PCMK__XE_ST_DEVICE_ID
#define PCMK__XA_ST_NOTIFY_DEACTIVATE
#define PCMK__XA_ST_ORIGIN
#define PCMK__XA_ST_DELAY
#define PCMK__XE_ST_HISTORY
#define PCMK__XA_RSC_PROVIDES
#define PCMK__XA_ST_TOLERANCE
#define PCMK__XA_ST_REMOTE_OP
#define PCMK__XA_T
#define PCMK__XA_SUBT
#define PCMK__XA_ST_OUTPUT
#define PCMK__XA_ST_DEVICE_ID
#define PCMK__XA_ST_NOTIFY_ACTIVATE
#define PCMK__XA_ST_CLIENTNAME
#define PCMK__XA_ST_OP
#define PCMK__XA_ST_DEVICE_ACTION
#define PCMK__XA_ST_TIMEOUT
#define PCMK__XE_ATTRIBUTES
#define PCMK__XE_STONITH_COMMAND
xmlXPathObject * pcmk__xpath_search(xmlDoc *doc, const char *path)
Definition xpath.c:137
xmlNode * pcmk__xpath_result(xmlXPathObject *xpath_obj, int index)
Definition xpath.c:65
xmlNode * pcmk__xpath_find_one(xmlDoc *doc, const char *path, uint8_t level)
Definition xpath.c:206