pacemaker 2.1.8-2.1.8~rc1
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
st_client.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2024 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#include <glib.h>
20
21#include <crm/crm.h>
22#include <crm/stonith-ng.h>
24#include <crm/common/xml.h>
25
26#include <crm/common/mainloop.h>
27
28#include "fencing_private.h"
29
31
32// Used as stonith_t:st_private
33typedef struct stonith_private_s {
34 char *token;
35 crm_ipc_t *ipc;
36 mainloop_io_t *source;
37 GHashTable *stonith_op_callback_table;
38 GList *notify_list;
39 int notify_refcnt;
40 bool notify_deletes;
41
42 void (*op_callback) (stonith_t * st, stonith_callback_data_t * data);
43
45
46// Used as stonith_event_t:opaque
47struct event_private {
49};
50
51typedef struct stonith_notify_client_s {
52 const char *event;
53 const char *obj_id; /* implement one day */
54 const char *obj_type; /* implement one day */
55 void (*notify) (stonith_t * st, stonith_event_t * e);
56 bool delete;
57
59
60typedef struct stonith_callback_client_s {
61 void (*callback) (stonith_t * st, stonith_callback_data_t * data);
62 const char *id;
63 void *user_data;
64 gboolean only_success;
65 gboolean allow_timeout_updates;
66 struct timer_rec_s *timer;
67
69
70struct notify_blob_s {
71 stonith_t *stonith;
72 xmlNode *xml;
73};
74
75struct timer_rec_s {
76 int call_id;
77 int timeout;
78 guint ref;
80};
81
82typedef int (*stonith_op_t) (const char *, int, const char *, xmlNode *,
83 xmlNode *, xmlNode *, xmlNode **, xmlNode **);
84
86xmlNode *stonith_create_op(int call_id, const char *token, const char *op, xmlNode * data,
87 int call_options);
88static int stonith_send_command(stonith_t *stonith, const char *op,
89 xmlNode *data, xmlNode **output_data,
90 int call_options, int timeout);
91
92static void stonith_connection_destroy(gpointer user_data);
93static void stonith_send_notification(gpointer data, gpointer user_data);
94static int stonith_api_del_notification(stonith_t *stonith,
95 const char *event);
104stonith_text2namespace(const char *namespace_s)
105{
106 if (pcmk__str_eq(namespace_s, "any", pcmk__str_null_matches)) {
107 return st_namespace_any;
108
109 } else if (!strcmp(namespace_s, "redhat")
110 || !strcmp(namespace_s, "stonith-ng")) {
111 return st_namespace_rhcs;
112
113 } else if (!strcmp(namespace_s, "internal")) {
115
116 } else if (!strcmp(namespace_s, "heartbeat")) {
117 return st_namespace_lha;
118 }
120}
121
129const char *
131{
132 switch (st_namespace) {
133 case st_namespace_any: return "any";
134 case st_namespace_rhcs: return "stonith-ng";
135 case st_namespace_internal: return "internal";
136 case st_namespace_lha: return "heartbeat";
137 default: break;
138 }
139 return "unsupported";
140}
141
151stonith_get_namespace(const char *agent, const char *namespace_s)
152{
153 if (pcmk__str_eq(namespace_s, "internal", pcmk__str_none)) {
155 }
156
157 if (stonith__agent_is_rhcs(agent)) {
158 return st_namespace_rhcs;
159 }
160
161#if HAVE_STONITH_STONITH_H
162 if (stonith__agent_is_lha(agent)) {
163 return st_namespace_lha;
164 }
165#endif
166
167 crm_err("Unknown fence agent: %s", agent);
169}
170
171gboolean
173{
174 gboolean rv = FALSE;
175 stonith_t *stonith_api = st?st:stonith_api_new();
176 char *list = NULL;
177
178 if(stonith_api) {
179 if (stonith_api->state == stonith_disconnected) {
180 int rc = stonith_api->cmds->connect(stonith_api, "stonith-api", NULL);
181
182 if (rc != pcmk_ok) {
183 crm_err("Failed connecting to Stonith-API for watchdog-fencing-query.");
184 }
185 }
186
187 if (stonith_api->state != stonith_disconnected) {
188 /* caveat!!!
189 * this might fail when when stonithd is just updating the device-list
190 * probably something we should fix as well for other api-calls */
191 int rc = stonith_api->cmds->list(stonith_api, st_opt_sync_call, STONITH_WATCHDOG_ID, &list, 0);
192 if ((rc != pcmk_ok) || (list == NULL)) {
193 /* due to the race described above it can happen that
194 * we drop in here - so as not to make remote nodes
195 * panic on that answer
196 */
197 if (rc == -ENODEV) {
198 crm_notice("Cluster does not have watchdog fencing device");
199 } else {
200 crm_warn("Could not check for watchdog fencing device: %s",
201 pcmk_strerror(rc));
202 }
203 } else if (list[0] == '\0') {
204 rv = TRUE;
205 } else {
206 GList *targets = stonith__parse_targets(list);
207 rv = pcmk__str_in_list(node, targets, pcmk__str_casei);
208 g_list_free_full(targets, free);
209 }
210 free(list);
211 if (!st) {
212 /* if we're provided the api we still might have done the
213 * connection - but let's assume the caller won't bother
214 */
215 stonith_api->cmds->disconnect(stonith_api);
216 }
217 }
218
219 if (!st) {
220 stonith_api_delete(stonith_api);
221 }
222 } else {
223 crm_err("Stonith-API for watchdog-fencing-query couldn't be created.");
224 }
225 crm_trace("Pacemaker assumes node %s %sto do watchdog-fencing.",
226 node, rv?"":"not ");
227 return rv;
228}
229
230gboolean
235
236/* when cycling through the list we don't want to delete items
237 so just mark them and when we know nobody is using the list
238 loop over it to remove the marked items
239 */
240static void
241foreach_notify_entry (stonith_private_t *private,
242 GFunc func,
243 gpointer user_data)
244{
245 private->notify_refcnt++;
246 g_list_foreach(private->notify_list, func, user_data);
247 private->notify_refcnt--;
248 if ((private->notify_refcnt == 0) &&
249 private->notify_deletes) {
250 GList *list_item = private->notify_list;
251
252 private->notify_deletes = FALSE;
253 while (list_item != NULL)
254 {
255 stonith_notify_client_t *list_client = list_item->data;
256 GList *next = g_list_next(list_item);
257
258 if (list_client->delete) {
259 free(list_client);
260 private->notify_list =
261 g_list_delete_link(private->notify_list, list_item);
262 }
263 list_item = next;
264 }
265 }
266}
267
268static void
269stonith_connection_destroy(gpointer user_data)
270{
271 stonith_t *stonith = user_data;
272 stonith_private_t *native = NULL;
273 struct notify_blob_s blob;
274
275 crm_trace("Sending destroyed notification");
276 blob.stonith = stonith;
277 blob.xml = pcmk__xe_create(NULL, PCMK__XE_NOTIFY);
278
279 native = stonith->st_private;
280 native->ipc = NULL;
281 native->source = NULL;
282
283 free(native->token); native->token = NULL;
284 stonith->state = stonith_disconnected;
287
288 foreach_notify_entry(native, stonith_send_notification, &blob);
289 free_xml(blob.xml);
290}
291
292xmlNode *
294 const char *agent,
295 const stonith_key_value_t *params,
296 const char *rsc_provides)
297{
299 xmlNode *args = pcmk__xe_create(data, PCMK__XE_ATTRIBUTES);
300
301#if HAVE_STONITH_STONITH_H
302 if (namespace == st_namespace_any) {
303 namespace = stonith_get_namespace(agent, NULL);
304 }
305 if (namespace == st_namespace_lha) {
306 hash2field((gpointer) "plugin", (gpointer) agent, args);
307 agent = "fence_legacy";
308 }
309#endif
310
314 if ((namespace != st_namespace_any) && (namespace != st_namespace_invalid)) {
316 stonith_namespace2text(namespace));
317 }
318 if (rsc_provides) {
319 crm_xml_add(data, PCMK__XA_RSC_PROVIDES, rsc_provides);
320 }
321
322 for (; params; params = params->next) {
323 hash2field((gpointer) params->key, (gpointer) params->value, args);
324 }
325
326 return data;
327}
328
329static int
330stonith_api_register_device(stonith_t *st, int call_options,
331 const char *id, const char *namespace_s,
332 const char *agent,
333 const stonith_key_value_t *params)
334{
335 int rc = 0;
336 xmlNode *data = NULL;
337
339 stonith_text2namespace(namespace_s),
340 agent, params, NULL);
341
342 rc = stonith_send_command(st, STONITH_OP_DEVICE_ADD, data, NULL, call_options, 0);
343 free_xml(data);
344
345 return rc;
346}
347
348static int
349stonith_api_remove_device(stonith_t * st, int call_options, const char *name)
350{
351 int rc = 0;
352 xmlNode *data = NULL;
353
357 rc = stonith_send_command(st, STONITH_OP_DEVICE_DEL, data, NULL, call_options, 0);
358 free_xml(data);
359
360 return rc;
361}
362
363static int
364stonith_api_remove_level_full(stonith_t *st, int options,
365 const char *node, const char *pattern,
366 const char *attr, const char *value, int level)
367{
368 int rc = 0;
369 xmlNode *data = NULL;
370
371 CRM_CHECK(node || pattern || (attr && value), return -EINVAL);
372
375
376 if (node) {
378
379 } else if (pattern) {
381
382 } else {
385 }
386
388 rc = stonith_send_command(st, STONITH_OP_LEVEL_DEL, data, NULL, options, 0);
389 free_xml(data);
390
391 return rc;
392}
393
394static int
395stonith_api_remove_level(stonith_t * st, int options, const char *node, int level)
396{
397 return stonith_api_remove_level_full(st, options, node,
398 NULL, NULL, NULL, level);
399}
400
416xmlNode *
417create_level_registration_xml(const char *node, const char *pattern,
418 const char *attr, const char *value,
419 int level, const stonith_key_value_t *device_list)
420{
421 GString *list = NULL;
422 xmlNode *data;
423
424 CRM_CHECK(node || pattern || (attr && value), return NULL);
425
427
431
432 if (node) {
434
435 } else if (pattern) {
437
438 } else {
441 }
442
443 for (; device_list; device_list = device_list->next) {
444 pcmk__add_separated_word(&list, 1024, device_list->value, ",");
445 }
446
447 if (list != NULL) {
448 crm_xml_add(data, PCMK_XA_DEVICES, (const char *) list->str);
449 g_string_free(list, TRUE);
450 }
451 return data;
452}
453
454static int
455stonith_api_register_level_full(stonith_t *st, int options, const char *node,
456 const char *pattern, const char *attr,
457 const char *value, int level,
458 const stonith_key_value_t *device_list)
459{
460 int rc = 0;
461 xmlNode *data = create_level_registration_xml(node, pattern, attr, value,
462 level, device_list);
463 CRM_CHECK(data != NULL, return -EINVAL);
464
465 rc = stonith_send_command(st, STONITH_OP_LEVEL_ADD, data, NULL, options, 0);
466 free_xml(data);
467
468 return rc;
469}
470
471static int
472stonith_api_register_level(stonith_t * st, int options, const char *node, int level,
473 const stonith_key_value_t * device_list)
474{
475 return stonith_api_register_level_full(st, options, node, NULL, NULL, NULL,
476 level, device_list);
477}
478
479static int
480stonith_api_device_list(stonith_t *stonith, int call_options,
481 const char *namespace_s, stonith_key_value_t **devices,
482 int timeout)
483{
484 int count = 0;
485 enum stonith_namespace ns = stonith_text2namespace(namespace_s);
486
487 if (devices == NULL) {
488 crm_err("Parameter error: stonith_api_device_list");
489 return -EFAULT;
490 }
491
492#if HAVE_STONITH_STONITH_H
493 // Include Linux-HA agents if requested
494 if ((ns == st_namespace_any) || (ns == st_namespace_lha)) {
495 count += stonith__list_lha_agents(devices);
496 }
497#endif
498
499 // Include Red Hat agents if requested
500 if ((ns == st_namespace_any) || (ns == st_namespace_rhcs)) {
501 count += stonith__list_rhcs_agents(devices);
502 }
503
504 return count;
505}
506
507// See stonith_api_operations_t:metadata() documentation
508static int
509stonith_api_device_metadata(stonith_t *stonith, int call_options,
510 const char *agent, const char *namespace_s,
511 char **output, int timeout_sec)
512{
513 /* By executing meta-data directly, we can get it from stonith_admin when
514 * the cluster is not running, which is important for higher-level tools.
515 */
516
517 enum stonith_namespace ns = stonith_get_namespace(agent, namespace_s);
518
519 if (timeout_sec <= 0) {
521 }
522
523 crm_trace("Looking up metadata for %s agent %s",
524 stonith_namespace2text(ns), agent);
525
526 switch (ns) {
528 return stonith__rhcs_metadata(agent, timeout_sec, output);
529
530#if HAVE_STONITH_STONITH_H
531 case st_namespace_lha:
532 return stonith__lha_metadata(agent, timeout_sec, output);
533#endif
534
535 default:
536 crm_err("Can't get fence agent '%s' meta-data: No such agent",
537 agent);
538 break;
539 }
540 return -ENODEV;
541}
542
543static int
544stonith_api_query(stonith_t * stonith, int call_options, const char *target,
545 stonith_key_value_t ** devices, int timeout)
546{
547 int rc = 0, lpc = 0, max = 0;
548
549 xmlNode *data = NULL;
550 xmlNode *output = NULL;
551 xmlXPathObjectPtr xpathObj = NULL;
552
553 CRM_CHECK(devices != NULL, return -EINVAL);
554
559 rc = stonith_send_command(stonith, STONITH_OP_QUERY, data, &output, call_options, timeout);
560
561 if (rc < 0) {
562 return rc;
563 }
564
565 xpathObj = xpath_search(output, "//@agent");
566 if (xpathObj) {
567 max = numXpathResults(xpathObj);
568
569 for (lpc = 0; lpc < max; lpc++) {
570 xmlNode *match = getXpathResult(xpathObj, lpc);
571
572 CRM_LOG_ASSERT(match != NULL);
573 if(match != NULL) {
574 xmlChar *match_path = xmlGetNodePath(match);
575
576 crm_info("%s[%d] = %s", "//@agent", lpc, match_path);
577 free(match_path);
578 *devices = stonith_key_value_add(*devices, NULL,
579 crm_element_value(match,
580 PCMK_XA_ID));
581 }
582 }
583
584 freeXpathObject(xpathObj);
585 }
586
587 free_xml(output);
588 free_xml(data);
589 return max;
590}
591
604static int
605stonith_api_call(stonith_t *stonith, int call_options, const char *id,
606 const char *action, const char *target, int timeout_sec,
607 xmlNode **output)
608{
609 int rc = 0;
610 xmlNode *data = NULL;
611
617
618 rc = stonith_send_command(stonith, STONITH_OP_EXEC, data, output,
619 call_options, timeout_sec);
620 free_xml(data);
621
622 return rc;
623}
624
625static int
626stonith_api_list(stonith_t * stonith, int call_options, const char *id, char **list_info,
627 int timeout)
628{
629 int rc;
630 xmlNode *output = NULL;
631
632 rc = stonith_api_call(stonith, call_options, id, PCMK_ACTION_LIST, NULL,
633 timeout, &output);
634
635 if (output && list_info) {
636 const char *list_str;
637
638 list_str = crm_element_value(output, PCMK__XA_ST_OUTPUT);
639
640 if (list_str) {
641 *list_info = strdup(list_str);
642 }
643 }
644
645 if (output) {
646 free_xml(output);
647 }
648
649 return rc;
650}
651
652static int
653stonith_api_monitor(stonith_t * stonith, int call_options, const char *id, int timeout)
654{
655 return stonith_api_call(stonith, call_options, id, PCMK_ACTION_MONITOR,
656 NULL, timeout, NULL);
657}
658
659static int
660stonith_api_status(stonith_t * stonith, int call_options, const char *id, const char *port,
661 int timeout)
662{
663 return stonith_api_call(stonith, call_options, id, PCMK_ACTION_STATUS, port,
664 timeout, NULL);
665}
666
667static int
668stonith_api_fence_with_delay(stonith_t * stonith, int call_options, const char *node,
669 const char *action, int timeout, int tolerance, int delay)
670{
671 int rc = 0;
672 xmlNode *data = NULL;
673
674 data = pcmk__xe_create(NULL, __func__);
680
681 rc = stonith_send_command(stonith, STONITH_OP_FENCE, data, NULL, call_options, timeout);
682 free_xml(data);
683
684 return rc;
685}
686
687static int
688stonith_api_fence(stonith_t * stonith, int call_options, const char *node, const char *action,
689 int timeout, int tolerance)
690{
691 return stonith_api_fence_with_delay(stonith, call_options, node, action,
692 timeout, tolerance, 0);
693}
694
695static int
696stonith_api_confirm(stonith_t * stonith, int call_options, const char *target)
697{
699 return stonith_api_fence(stonith, call_options, target, PCMK_ACTION_OFF, 0,
700 0);
701}
702
703static int
704stonith_api_history(stonith_t * stonith, int call_options, const char *node,
705 stonith_history_t ** history, int timeout)
706{
707 int rc = 0;
708 xmlNode *data = NULL;
709 xmlNode *output = NULL;
710 stonith_history_t *last = NULL;
711
712 *history = NULL;
713
714 if (node) {
715 data = pcmk__xe_create(NULL, __func__);
717 }
718
719 stonith__set_call_options(call_options, node, st_opt_sync_call);
720 rc = stonith_send_command(stonith, STONITH_OP_FENCE_HISTORY, data, &output,
721 call_options, timeout);
722 free_xml(data);
723
724 if (rc == 0) {
725 xmlNode *op = NULL;
726 xmlNode *reply = get_xpath_object("//" PCMK__XE_ST_HISTORY, output,
727 LOG_NEVER);
728
729 for (op = pcmk__xe_first_child(reply, NULL, NULL, NULL); op != NULL;
730 op = pcmk__xe_next(op)) {
732 long long completed;
733 long long completed_nsec = 0L;
734
735 kvp = pcmk__assert_alloc(1, sizeof(stonith_history_t));
741 crm_element_value_ll(op, PCMK__XA_ST_DATE, &completed);
742 kvp->completed = (time_t) completed;
743 crm_element_value_ll(op, PCMK__XA_ST_DATE_NSEC, &completed_nsec);
744 kvp->completed_nsec = completed_nsec;
747
748 if (last) {
749 last->next = kvp;
750 } else {
751 *history = kvp;
752 }
753 last = kvp;
754 }
755 }
756
757 free_xml(output);
758
759 return rc;
760}
761
763{
764 stonith_history_t *hp, *hp_old;
765
766 for (hp = history; hp; hp_old = hp, hp = hp->next, free(hp_old)) {
767 free(hp->target);
768 free(hp->action);
769 free(hp->origin);
770 free(hp->delegate);
771 free(hp->client);
772 free(hp->exit_reason);
773 }
774}
775
776static gint
777stonithlib_GCompareFunc(gconstpointer a, gconstpointer b)
778{
779 int rc = 0;
780 const stonith_notify_client_t *a_client = a;
781 const stonith_notify_client_t *b_client = b;
782
783 if (a_client->delete || b_client->delete) {
784 /* make entries marked for deletion not findable */
785 return -1;
786 }
787 CRM_CHECK(a_client->event != NULL && b_client->event != NULL, return 0);
788 rc = strcmp(a_client->event, b_client->event);
789 if (rc == 0) {
790 if (a_client->notify == NULL || b_client->notify == NULL) {
791 return 0;
792
793 } else if (a_client->notify == b_client->notify) {
794 return 0;
795
796 } else if (((long)a_client->notify) < ((long)b_client->notify)) {
797 crm_err("callbacks for %s are not equal: %p vs. %p",
798 a_client->event, a_client->notify, b_client->notify);
799 return -1;
800 }
801 crm_err("callbacks for %s are not equal: %p vs. %p",
802 a_client->event, a_client->notify, b_client->notify);
803 return 1;
804 }
805 return rc;
806}
807
808xmlNode *
809stonith_create_op(int call_id, const char *token, const char *op, xmlNode * data, int call_options)
810{
811 xmlNode *op_msg = NULL;
812
813 CRM_CHECK(token != NULL, return NULL);
814
817 crm_xml_add(op_msg, PCMK__XA_ST_OP, op);
818 crm_xml_add_int(op_msg, PCMK__XA_ST_CALLID, call_id);
819 crm_trace("Sending call options: %.8lx, %d", (long)call_options, call_options);
820 crm_xml_add_int(op_msg, PCMK__XA_ST_CALLOPT, call_options);
821
822 if (data != NULL) {
823 xmlNode *wrapper = pcmk__xe_create(op_msg, PCMK__XE_ST_CALLDATA);
824
825 pcmk__xml_copy(wrapper, data);
826 }
827
828 return op_msg;
829}
830
831static void
832stonith_destroy_op_callback(gpointer data)
833{
835
836 if (blob->timer && blob->timer->ref > 0) {
837 g_source_remove(blob->timer->ref);
838 }
839 free(blob->timer);
840 free(blob);
841}
842
843static int
844stonith_api_signoff(stonith_t * stonith)
845{
846 stonith_private_t *native = stonith->st_private;
847
848 crm_debug("Disconnecting from the fencer");
849
850 if (native->source != NULL) {
851 /* Attached to mainloop */
852 mainloop_del_ipc_client(native->source);
853 native->source = NULL;
854 native->ipc = NULL;
855
856 } else if (native->ipc) {
857 /* Not attached to mainloop */
858 crm_ipc_t *ipc = native->ipc;
859
860 native->ipc = NULL;
861 crm_ipc_close(ipc);
862 crm_ipc_destroy(ipc);
863 }
864
865 free(native->token); native->token = NULL;
866 stonith->state = stonith_disconnected;
867 return pcmk_ok;
868}
869
870static int
871stonith_api_del_callback(stonith_t * stonith, int call_id, bool all_callbacks)
872{
873 stonith_private_t *private = stonith->st_private;
874
875 if (all_callbacks) {
876 private->op_callback = NULL;
877 g_hash_table_destroy(private->stonith_op_callback_table);
878 private->stonith_op_callback_table = pcmk__intkey_table(stonith_destroy_op_callback);
879
880 } else if (call_id == 0) {
881 private->op_callback = NULL;
882
883 } else {
884 pcmk__intkey_table_remove(private->stonith_op_callback_table, call_id);
885 }
886 return pcmk_ok;
887}
888
900static void
901invoke_fence_action_callback(stonith_t *st, int call_id,
903 void *userdata,
904 void (*callback) (stonith_t *st,
906{
908
909 data.call_id = call_id;
911 data.userdata = userdata;
912 data.opaque = (void *) result;
913
914 callback(st, &data);
915}
916
928static void
929invoke_registered_callbacks(stonith_t *stonith, const xmlNode *msg, int call_id)
930{
931 stonith_private_t *private = NULL;
932 stonith_callback_client_t *cb_info = NULL;
934
935 CRM_CHECK(stonith != NULL, return);
936 CRM_CHECK(stonith->st_private != NULL, return);
937
938 private = stonith->st_private;
939
940 if (msg == NULL) {
941 // Fencer didn't reply in time
943 "Fencer accepted request but did not reply in time");
944 CRM_LOG_ASSERT(call_id > 0);
945
946 } else {
947 // We have the fencer reply
948 if ((crm_element_value_int(msg, PCMK__XA_ST_CALLID, &call_id) != 0)
949 || (call_id <= 0)) {
950 crm_log_xml_warn(msg, "Bad fencer reply");
951 }
953 }
954
955 if (call_id > 0) {
956 cb_info = pcmk__intkey_table_lookup(private->stonith_op_callback_table,
957 call_id);
958 }
959
960 if ((cb_info != NULL) && (cb_info->callback != NULL)
961 && (pcmk__result_ok(&result) || !(cb_info->only_success))) {
962 crm_trace("Invoking callback %s for call %d",
963 pcmk__s(cb_info->id, "without ID"), call_id);
964 invoke_fence_action_callback(stonith, call_id, &result,
965 cb_info->user_data, cb_info->callback);
966
967 } else if ((private->op_callback == NULL) && !pcmk__result_ok(&result)) {
968 crm_warn("Fencing action without registered callback failed: %d (%s%s%s)",
970 pcmk_exec_status_str(result.execution_status),
971 ((result.exit_reason == NULL)? "" : ": "),
972 ((result.exit_reason == NULL)? "" : result.exit_reason));
973 crm_log_xml_debug(msg, "Failed fence update");
974 }
975
976 if (private->op_callback != NULL) {
977 crm_trace("Invoking global callback for call %d", call_id);
978 invoke_fence_action_callback(stonith, call_id, &result, NULL,
979 private->op_callback);
980 }
981
982 if (cb_info != NULL) {
983 stonith_api_del_callback(stonith, call_id, FALSE);
984 }
986}
987
988static gboolean
989stonith_async_timeout_handler(gpointer data)
990{
991 struct timer_rec_s *timer = data;
992
993 crm_err("Async call %d timed out after %dms", timer->call_id, timer->timeout);
994 invoke_registered_callbacks(timer->stonith, NULL, timer->call_id);
995
996 /* Always return TRUE, never remove the handler
997 * We do that in stonith_del_callback()
998 */
999 return TRUE;
1000}
1001
1002static void
1003set_callback_timeout(stonith_callback_client_t * callback, stonith_t * stonith, int call_id,
1004 int timeout)
1005{
1006 struct timer_rec_s *async_timer = callback->timer;
1007
1008 if (timeout <= 0) {
1009 return;
1010 }
1011
1012 if (!async_timer) {
1013 async_timer = pcmk__assert_alloc(1, sizeof(struct timer_rec_s));
1014 callback->timer = async_timer;
1015 }
1016
1017 async_timer->stonith = stonith;
1018 async_timer->call_id = call_id;
1019 /* Allow a fair bit of grace to allow the server to tell us of a timeout
1020 * This is only a fallback
1021 */
1022 async_timer->timeout = (timeout + 60) * 1000;
1023 if (async_timer->ref) {
1024 g_source_remove(async_timer->ref);
1025 }
1026 async_timer->ref =
1027 g_timeout_add(async_timer->timeout, stonith_async_timeout_handler, async_timer);
1028}
1029
1030static void
1031update_callback_timeout(int call_id, int timeout, stonith_t * st)
1032{
1033 stonith_callback_client_t *callback = NULL;
1034 stonith_private_t *private = st->st_private;
1035
1036 callback = pcmk__intkey_table_lookup(private->stonith_op_callback_table,
1037 call_id);
1038 if (!callback || !callback->allow_timeout_updates) {
1039 return;
1040 }
1041
1042 set_callback_timeout(callback, st, call_id, timeout);
1043}
1044
1045static int
1046stonith_dispatch_internal(const char *buffer, ssize_t length, gpointer userdata)
1047{
1048 const char *type = NULL;
1049 struct notify_blob_s blob;
1050
1051 stonith_t *st = userdata;
1052 stonith_private_t *private = NULL;
1053
1054 CRM_ASSERT(st != NULL);
1055 private = st->st_private;
1056
1057 blob.stonith = st;
1058 blob.xml = pcmk__xml_parse(buffer);
1059 if (blob.xml == NULL) {
1060 crm_warn("Received malformed message from fencer: %s", buffer);
1061 return 0;
1062 }
1063
1064 /* do callbacks */
1065 type = crm_element_value(blob.xml, PCMK__XA_T);
1066 crm_trace("Activating %s callbacks...", type);
1067
1068 if (pcmk__str_eq(type, PCMK__VALUE_STONITH_NG, pcmk__str_none)) {
1069 invoke_registered_callbacks(st, blob.xml, 0);
1070
1071 } else if (pcmk__str_eq(type, PCMK__VALUE_ST_NOTIFY, pcmk__str_none)) {
1072 foreach_notify_entry(private, stonith_send_notification, &blob);
1073
1074 } else if (pcmk__str_eq(type, PCMK__VALUE_ST_ASYNC_TIMEOUT_VALUE,
1075 pcmk__str_none)) {
1076 int call_id = 0;
1077 int timeout = 0;
1078
1080 crm_element_value_int(blob.xml, PCMK__XA_ST_CALLID, &call_id);
1081
1082 update_callback_timeout(call_id, timeout, st);
1083 } else {
1084 crm_err("Unknown message type: %s", type);
1085 crm_log_xml_warn(blob.xml, "BadReply");
1086 }
1087
1088 free_xml(blob.xml);
1089 return 1;
1090}
1091
1092static int
1093stonith_api_signon(stonith_t * stonith, const char *name, int *stonith_fd)
1094{
1095 int rc = pcmk_ok;
1096 stonith_private_t *native = NULL;
1097 const char *display_name = name? name : "client";
1098
1099 struct ipc_client_callbacks st_callbacks = {
1100 .dispatch = stonith_dispatch_internal,
1101 .destroy = stonith_connection_destroy
1102 };
1103
1104 CRM_CHECK(stonith != NULL, return -EINVAL);
1105
1106 native = stonith->st_private;
1107 CRM_ASSERT(native != NULL);
1108
1109 crm_debug("Attempting fencer connection by %s with%s mainloop",
1110 display_name, (stonith_fd? "out" : ""));
1111
1113 if (stonith_fd) {
1114 /* No mainloop */
1115 native->ipc = crm_ipc_new("stonith-ng", 0);
1116 if (native->ipc != NULL) {
1117 rc = pcmk__connect_generic_ipc(native->ipc);
1118 if (rc == pcmk_rc_ok) {
1119 rc = pcmk__ipc_fd(native->ipc, stonith_fd);
1120 if (rc != pcmk_rc_ok) {
1121 crm_debug("Couldn't get file descriptor for IPC: %s",
1122 pcmk_rc_str(rc));
1123 }
1124 }
1125 if (rc != pcmk_rc_ok) {
1126 crm_ipc_close(native->ipc);
1127 crm_ipc_destroy(native->ipc);
1128 native->ipc = NULL;
1129 }
1130 }
1131
1132 } else {
1133 /* With mainloop */
1134 native->source =
1135 mainloop_add_ipc_client("stonith-ng", G_PRIORITY_MEDIUM, 0, stonith, &st_callbacks);
1136 native->ipc = mainloop_get_ipc_client(native->source);
1137 }
1138
1139 if (native->ipc == NULL) {
1140 rc = -ENOTCONN;
1141 } else {
1142 xmlNode *reply = NULL;
1143 xmlNode *hello = pcmk__xe_create(NULL, PCMK__XE_STONITH_COMMAND);
1144
1148 rc = crm_ipc_send(native->ipc, hello, crm_ipc_client_response, -1, &reply);
1149
1150 if (rc < 0) {
1151 crm_debug("Couldn't register with the fencer: %s "
1152 CRM_XS " rc=%d", pcmk_strerror(rc), rc);
1153 rc = -ECOMM;
1154
1155 } else if (reply == NULL) {
1156 crm_debug("Couldn't register with the fencer: no reply");
1157 rc = -EPROTO;
1158
1159 } else {
1160 const char *msg_type = crm_element_value(reply, PCMK__XA_ST_OP);
1161
1162 native->token = crm_element_value_copy(reply, PCMK__XA_ST_CLIENTID);
1163 if (!pcmk__str_eq(msg_type, CRM_OP_REGISTER, pcmk__str_none)) {
1164 crm_debug("Couldn't register with the fencer: invalid reply type '%s'",
1165 (msg_type? msg_type : "(missing)"));
1166 crm_log_xml_debug(reply, "Invalid fencer reply");
1167 rc = -EPROTO;
1168
1169 } else if (native->token == NULL) {
1170 crm_debug("Couldn't register with the fencer: no token in reply");
1171 crm_log_xml_debug(reply, "Invalid fencer reply");
1172 rc = -EPROTO;
1173
1174 } else {
1175 crm_debug("Connection to fencer by %s succeeded (registration token: %s)",
1176 display_name, native->token);
1177 rc = pcmk_ok;
1178 }
1179 }
1180
1181 free_xml(reply);
1182 free_xml(hello);
1183 }
1184
1185 if (rc != pcmk_ok) {
1186 crm_debug("Connection attempt to fencer by %s failed: %s "
1187 CRM_XS " rc=%d", display_name, pcmk_strerror(rc), rc);
1188 stonith->cmds->disconnect(stonith);
1189 }
1190 return rc;
1191}
1192
1193static int
1194stonith_set_notification(stonith_t * stonith, const char *callback, int enabled)
1195{
1196 int rc = pcmk_ok;
1197 xmlNode *notify_msg = pcmk__xe_create(NULL, __func__);
1198 stonith_private_t *native = stonith->st_private;
1199
1200 if (stonith->state != stonith_disconnected) {
1201
1203 if (enabled) {
1204 crm_xml_add(notify_msg, PCMK__XA_ST_NOTIFY_ACTIVATE, callback);
1205 } else {
1206 crm_xml_add(notify_msg, PCMK__XA_ST_NOTIFY_DEACTIVATE, callback);
1207 }
1208
1209 rc = crm_ipc_send(native->ipc, notify_msg, crm_ipc_client_response, -1, NULL);
1210 if (rc < 0) {
1211 crm_perror(LOG_DEBUG, "Couldn't register for fencing notifications: %d", rc);
1212 rc = -ECOMM;
1213 } else {
1214 rc = pcmk_ok;
1215 }
1216 }
1217
1218 free_xml(notify_msg);
1219 return rc;
1220}
1221
1222static int
1223stonith_api_add_notification(stonith_t * stonith, const char *event,
1224 void (*callback) (stonith_t * stonith, stonith_event_t * e))
1225{
1226 GList *list_item = NULL;
1227 stonith_notify_client_t *new_client = NULL;
1228 stonith_private_t *private = NULL;
1229
1230 private = stonith->st_private;
1231 crm_trace("Adding callback for %s events (%d)", event, g_list_length(private->notify_list));
1232
1233 new_client = pcmk__assert_alloc(1, sizeof(stonith_notify_client_t));
1234 new_client->event = event;
1235 new_client->notify = callback;
1236
1237 list_item = g_list_find_custom(private->notify_list, new_client, stonithlib_GCompareFunc);
1238
1239 if (list_item != NULL) {
1240 crm_warn("Callback already present");
1241 free(new_client);
1242 return -ENOTUNIQ;
1243
1244 } else {
1245 private->notify_list = g_list_append(private->notify_list, new_client);
1246
1247 stonith_set_notification(stonith, event, 1);
1248
1249 crm_trace("Callback added (%d)", g_list_length(private->notify_list));
1250 }
1251 return pcmk_ok;
1252}
1253
1254static void
1255del_notify_entry(gpointer data, gpointer user_data)
1256{
1258 stonith_t * stonith = user_data;
1259
1260 if (!entry->delete) {
1261 crm_debug("Removing callback for %s events", entry->event);
1262 stonith_api_del_notification(stonith, entry->event);
1263 }
1264}
1265
1266static int
1267stonith_api_del_notification(stonith_t * stonith, const char *event)
1268{
1269 GList *list_item = NULL;
1270 stonith_notify_client_t *new_client = NULL;
1271 stonith_private_t *private = stonith->st_private;
1272
1273 if (event == NULL) {
1274 foreach_notify_entry(private, del_notify_entry, stonith);
1275 crm_trace("Removed callback");
1276
1277 return pcmk_ok;
1278 }
1279
1280 crm_debug("Removing callback for %s events", event);
1281
1282 new_client = pcmk__assert_alloc(1, sizeof(stonith_notify_client_t));
1283 new_client->event = event;
1284 new_client->notify = NULL;
1285
1286 list_item = g_list_find_custom(private->notify_list, new_client, stonithlib_GCompareFunc);
1287
1288 stonith_set_notification(stonith, event, 0);
1289
1290 if (list_item != NULL) {
1291 stonith_notify_client_t *list_client = list_item->data;
1292
1293 if (private->notify_refcnt) {
1294 list_client->delete = TRUE;
1295 private->notify_deletes = TRUE;
1296 } else {
1297 private->notify_list = g_list_remove(private->notify_list, list_client);
1298 free(list_client);
1299 }
1300
1301 crm_trace("Removed callback");
1302
1303 } else {
1304 crm_trace("Callback not present");
1305 }
1306 free(new_client);
1307 return pcmk_ok;
1308}
1309
1310static int
1311stonith_api_add_callback(stonith_t * stonith, int call_id, int timeout, int options,
1312 void *user_data, const char *callback_name,
1313 void (*callback) (stonith_t * st, stonith_callback_data_t * data))
1314{
1315 stonith_callback_client_t *blob = NULL;
1316 stonith_private_t *private = NULL;
1317
1318 CRM_CHECK(stonith != NULL, return -EINVAL);
1319 CRM_CHECK(stonith->st_private != NULL, return -EINVAL);
1320 private = stonith->st_private;
1321
1322 if (call_id == 0) { // Add global callback
1323 private->op_callback = callback;
1324
1325 } else if (call_id < 0) { // Call failed immediately, so call callback now
1326 if (!(options & st_opt_report_only_success)) {
1328
1329 crm_trace("Call failed, calling %s: %s", callback_name, pcmk_strerror(call_id));
1331 stonith__legacy2status(call_id), NULL);
1332 invoke_fence_action_callback(stonith, call_id, &result,
1333 user_data, callback);
1334 } else {
1335 crm_warn("Fencer call failed: %s", pcmk_strerror(call_id));
1336 }
1337 return FALSE;
1338 }
1339
1341 blob->id = callback_name;
1342 blob->only_success = (options & st_opt_report_only_success) ? TRUE : FALSE;
1343 blob->user_data = user_data;
1344 blob->callback = callback;
1345 blob->allow_timeout_updates = (options & st_opt_timeout_updates) ? TRUE : FALSE;
1346
1347 if (timeout > 0) {
1348 set_callback_timeout(blob, stonith, call_id, timeout);
1349 }
1350
1351 pcmk__intkey_table_insert(private->stonith_op_callback_table, call_id,
1352 blob);
1353 crm_trace("Added callback to %s for call %d", callback_name, call_id);
1354
1355 return TRUE;
1356}
1357
1358static void
1359stonith_dump_pending_op(gpointer key, gpointer value, gpointer user_data)
1360{
1361 int call = GPOINTER_TO_INT(key);
1362 stonith_callback_client_t *blob = value;
1363
1364 crm_debug("Call %d (%s): pending", call, pcmk__s(blob->id, "no ID"));
1365}
1366
1367void
1369{
1370 stonith_private_t *private = stonith->st_private;
1371
1372 if (private->stonith_op_callback_table == NULL) {
1373 return;
1374 }
1375 return g_hash_table_foreach(private->stonith_op_callback_table, stonith_dump_pending_op, NULL);
1376}
1377
1385static xmlNode *
1386get_event_data_xml(xmlNode *msg, const char *ntype)
1387{
1388 char *data_addr = crm_strdup_printf("//%s", ntype);
1389 xmlNode *data = get_xpath_object(data_addr, msg, LOG_DEBUG);
1390
1391 free(data_addr);
1392 return data;
1393}
1394
1395/*
1396 <notify t="st_notify" subt="st_device_register" st_op="st_device_register" st_rc="0" >
1397 <st_calldata >
1398 <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" >
1399 <st_calldata >
1400 <st_device_id id="test-id" origin="create_device_registration_xml" agent="fence_virsh" namespace="stonith-ng" >
1401 <attributes ipaddr="localhost" pcmk-portmal="some-host=pcmk-1 pcmk-3=3,4" login="root" identity_file="/root/.ssh/id_dsa" />
1402 </st_device_id>
1403 </st_calldata>
1404 </stonith_command>
1405 </st_calldata>
1406 </notify>
1407
1408 <notify t="st_notify" subt="st_notify_fence" st_op="st_notify_fence" st_rc="0" >
1409 <st_calldata >
1410 <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" />
1411 </st_calldata>
1412 </notify>
1413*/
1414static stonith_event_t *
1415xml_to_event(xmlNode *msg)
1416{
1418 struct event_private *event_private = NULL;
1419
1420 event->opaque = pcmk__assert_alloc(1, sizeof(struct event_private));
1421 event_private = (struct event_private *) event->opaque;
1422
1423 crm_log_xml_trace(msg, "stonith_notify");
1424
1425 // All notification types have the operation result and notification subtype
1426 stonith__xe_get_result(msg, &event_private->result);
1427 event->operation = crm_element_value_copy(msg, PCMK__XA_ST_OP);
1428
1429 // @COMPAT The API originally provided the result as a legacy return code
1430 event->result = pcmk_rc2legacy(stonith__result2rc(&event_private->result));
1431
1432 // Some notification subtypes have additional information
1433
1434 if (pcmk__str_eq(event->operation, PCMK__VALUE_ST_NOTIFY_FENCE,
1435 pcmk__str_none)) {
1436 xmlNode *data = get_event_data_xml(msg, event->operation);
1437
1438 if (data == NULL) {
1439 crm_err("No data for %s event", event->operation);
1440 crm_log_xml_notice(msg, "BadEvent");
1441 } else {
1443 event->action = crm_element_value_copy(data,
1446 event->executioner = crm_element_value_copy(data,
1449 event->client_origin =
1452 }
1453
1454 } else if (pcmk__str_any_of(event->operation,
1457 NULL)) {
1458 xmlNode *data = get_event_data_xml(msg, event->operation);
1459
1460 if (data == NULL) {
1461 crm_err("No data for %s event", event->operation);
1462 crm_log_xml_notice(msg, "BadEvent");
1463 } else {
1465 }
1466 }
1467
1468 return event;
1469}
1470
1471static void
1472event_free(stonith_event_t * event)
1473{
1474 struct event_private *event_private = event->opaque;
1475
1476 free(event->id);
1477 free(event->type);
1478 free(event->message);
1479 free(event->operation);
1480 free(event->origin);
1481 free(event->action);
1482 free(event->target);
1483 free(event->executioner);
1484 free(event->device);
1485 free(event->client_origin);
1486 pcmk__reset_result(&event_private->result);
1487 free(event->opaque);
1488 free(event);
1489}
1490
1491static void
1492stonith_send_notification(gpointer data, gpointer user_data)
1493{
1494 struct notify_blob_s *blob = user_data;
1496 stonith_event_t *st_event = NULL;
1497 const char *event = NULL;
1498
1499 if (blob->xml == NULL) {
1500 crm_warn("Skipping callback - NULL message");
1501 return;
1502 }
1503
1504 event = crm_element_value(blob->xml, PCMK__XA_SUBT);
1505
1506 if (entry == NULL) {
1507 crm_warn("Skipping callback - NULL callback client");
1508 return;
1509
1510 } else if (entry->delete) {
1511 crm_trace("Skipping callback - marked for deletion");
1512 return;
1513
1514 } else if (entry->notify == NULL) {
1515 crm_warn("Skipping callback - NULL callback");
1516 return;
1517
1518 } else if (!pcmk__str_eq(entry->event, event, pcmk__str_none)) {
1519 crm_trace("Skipping callback - event mismatch %p/%s vs. %s", entry, entry->event, event);
1520 return;
1521 }
1522
1523 st_event = xml_to_event(blob->xml);
1524
1525 crm_trace("Invoking callback for %p/%s event...", entry, event);
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 CRM_ASSERT(stonith && stonith->st_private && op);
1558 native = stonith->st_private;
1559
1560 if (output_data != NULL) {
1561 *output_data = NULL;
1562 }
1563
1564 if ((stonith->state == stonith_disconnected) || (native->token == NULL)) {
1565 return -ENOTCONN;
1566 }
1567
1568 /* Increment the call ID, which must be positive to avoid conflicting with
1569 * error codes. This shouldn't be a problem unless the client mucked with
1570 * it or the counter wrapped around.
1571 */
1572 stonith->call_id++;
1573 if (stonith->call_id < 1) {
1574 stonith->call_id = 1;
1575 }
1576
1577 op_msg = stonith_create_op(stonith->call_id, native->token, op, data, call_options);
1578 if (op_msg == NULL) {
1579 return -EINVAL;
1580 }
1581
1583 crm_trace("Sending %s message to fencer with timeout %ds", op, timeout);
1584
1585 if (data) {
1586 const char *delay_s = crm_element_value(data, PCMK__XA_ST_DELAY);
1587
1588 if (delay_s) {
1589 crm_xml_add(op_msg, PCMK__XA_ST_DELAY, delay_s);
1590 }
1591 }
1592
1593 {
1594 enum crm_ipc_flags ipc_flags = crm_ipc_flags_none;
1595
1596 if (call_options & st_opt_sync_call) {
1597 pcmk__set_ipc_flags(ipc_flags, "stonith command",
1599 }
1600 rc = crm_ipc_send(native->ipc, op_msg, ipc_flags,
1601 1000 * (timeout + 60), &op_reply);
1602 }
1603 free_xml(op_msg);
1604
1605 if (rc < 0) {
1606 crm_perror(LOG_ERR, "Couldn't perform %s operation (timeout=%ds): %d", op, timeout, rc);
1607 rc = -ECOMM;
1608 goto done;
1609 }
1610
1611 crm_log_xml_trace(op_reply, "Reply");
1612
1613 if (!(call_options & st_opt_sync_call)) {
1614 crm_trace("Async call %d, returning", stonith->call_id);
1615 free_xml(op_reply);
1616 return stonith->call_id;
1617 }
1618
1619 crm_element_value_int(op_reply, PCMK__XA_ST_CALLID, &reply_id);
1620
1621 if (reply_id == stonith->call_id) {
1623
1624 crm_trace("Synchronous reply %d received", reply_id);
1625
1626 stonith__xe_get_result(op_reply, &result);
1629
1630 if ((call_options & st_opt_discard_reply) || output_data == NULL) {
1631 crm_trace("Discarding reply");
1632
1633 } else {
1634 *output_data = op_reply;
1635 op_reply = NULL; /* Prevent subsequent free */
1636 }
1637
1638 } else if (reply_id <= 0) {
1639 crm_err("Received bad reply: No id set");
1640 crm_log_xml_err(op_reply, "Bad reply");
1641 free_xml(op_reply);
1642 rc = -ENOMSG;
1643
1644 } else {
1645 crm_err("Received bad reply: %d (wanted %d)", reply_id, stonith->call_id);
1646 crm_log_xml_err(op_reply, "Old reply");
1647 free_xml(op_reply);
1648 rc = -ENOMSG;
1649 }
1650
1651 done:
1652 if (!crm_ipc_connected(native->ipc)) {
1653 crm_err("Fencer disconnected");
1654 free(native->token); native->token = NULL;
1655 stonith->state = stonith_disconnected;
1656 }
1657
1658 free_xml(op_reply);
1659 return rc;
1660}
1661
1662/* Not used with mainloop */
1663bool
1665{
1666 gboolean stay_connected = TRUE;
1667 stonith_private_t *private = NULL;
1668
1669 CRM_ASSERT(st != NULL);
1670 private = st->st_private;
1671
1672 while (crm_ipc_ready(private->ipc)) {
1673
1674 if (crm_ipc_read(private->ipc) > 0) {
1675 const char *msg = crm_ipc_buffer(private->ipc);
1676
1677 stonith_dispatch_internal(msg, strlen(msg), st);
1678 }
1679
1680 if (!crm_ipc_connected(private->ipc)) {
1681 crm_err("Connection closed");
1682 stay_connected = FALSE;
1683 }
1684 }
1685
1686 return stay_connected;
1687}
1688
1689static int
1690stonith_api_free(stonith_t * stonith)
1691{
1692 int rc = pcmk_ok;
1693
1694 crm_trace("Destroying %p", stonith);
1695
1696 if (stonith->state != stonith_disconnected) {
1697 crm_trace("Unregistering notifications and disconnecting %p first",
1698 stonith);
1699 stonith->cmds->remove_notification(stonith, NULL);
1700 rc = stonith->cmds->disconnect(stonith);
1701 }
1702
1703 if (stonith->state == stonith_disconnected) {
1704 stonith_private_t *private = stonith->st_private;
1705
1706 crm_trace("Removing %d callbacks", g_hash_table_size(private->stonith_op_callback_table));
1707 g_hash_table_destroy(private->stonith_op_callback_table);
1708
1709 crm_trace("Destroying %d notification clients", g_list_length(private->notify_list));
1710 g_list_free_full(private->notify_list, free);
1711
1712 free(stonith->st_private);
1713 free(stonith->cmds);
1714 free(stonith);
1715
1716 } else {
1717 crm_err("Not free'ing active connection: %s (%d)", pcmk_strerror(rc), rc);
1718 }
1719
1720 return rc;
1721}
1722
1723void
1725{
1726 crm_trace("Destroying %p", stonith);
1727 if(stonith) {
1728 stonith->cmds->free(stonith);
1729 }
1730}
1731
1732static int
1733stonith_api_validate(stonith_t *st, int call_options, const char *rsc_id,
1734 const char *namespace_s, const char *agent,
1735 const stonith_key_value_t *params, int timeout_sec,
1736 char **output, char **error_output)
1737{
1738 /* Validation should be done directly via the agent, so we can get it from
1739 * stonith_admin when the cluster is not running, which is important for
1740 * higher-level tools.
1741 */
1742
1743 int rc = pcmk_ok;
1744
1745 /* Use a dummy node name in case the agent requires a target. We assume the
1746 * actual target doesn't matter for validation purposes (if in practice,
1747 * that is incorrect, we will need to allow the caller to pass the target).
1748 */
1749 const char *target = "node1";
1750 const char *host_arg = NULL;
1751
1752 GHashTable *params_table = pcmk__strkey_table(free, free);
1753
1754 // Convert parameter list to a hash table
1755 for (; params; params = params->next) {
1756 if (pcmk__str_eq(params->key, PCMK_STONITH_HOST_ARGUMENT,
1757 pcmk__str_none)) {
1758 host_arg = params->value;
1759 }
1760 if (!pcmk_stonith_param(params->key)) {
1761 pcmk__insert_dup(params_table, params->key, params->value);
1762 }
1763 }
1764
1765#if SUPPORT_CIBSECRETS
1766 rc = pcmk__substitute_secrets(rsc_id, params_table);
1767 if (rc != pcmk_rc_ok) {
1768 crm_warn("Could not replace secret parameters for validation of %s: %s",
1769 agent, pcmk_rc_str(rc));
1770 // rc is standard return value, don't return it in this function
1771 }
1772#endif
1773
1774 if (output) {
1775 *output = NULL;
1776 }
1777 if (error_output) {
1778 *error_output = NULL;
1779 }
1780
1781 if (timeout_sec <= 0) {
1782 timeout_sec = PCMK_DEFAULT_METADATA_TIMEOUT_MS; // Questionable
1783 }
1784
1785 switch (stonith_get_namespace(agent, namespace_s)) {
1786 case st_namespace_rhcs:
1787 rc = stonith__rhcs_validate(st, call_options, target, agent,
1788 params_table, host_arg, timeout_sec,
1789 output, error_output);
1790 break;
1791
1792#if HAVE_STONITH_STONITH_H
1793 case st_namespace_lha:
1794 rc = stonith__lha_validate(st, call_options, target, agent,
1795 params_table, timeout_sec, output,
1796 error_output);
1797 break;
1798#endif
1799
1801 errno = ENOENT;
1802 rc = -errno;
1803
1804 if (error_output) {
1805 *error_output = crm_strdup_printf("Agent %s not found", agent);
1806 } else {
1807 crm_err("Agent %s not found", agent);
1808 }
1809
1810 break;
1811
1812 default:
1813 errno = EOPNOTSUPP;
1814 rc = -errno;
1815
1816 if (error_output) {
1817 *error_output = crm_strdup_printf("Agent %s does not support validation",
1818 agent);
1819 } else {
1820 crm_err("Agent %s does not support validation", agent);
1821 }
1822
1823 break;
1824 }
1825
1826 g_hash_table_destroy(params_table);
1827 return rc;
1828}
1829
1830stonith_t *
1832{
1833 stonith_t *new_stonith = NULL;
1834 stonith_private_t *private = NULL;
1835
1836 new_stonith = calloc(1, sizeof(stonith_t));
1837 if (new_stonith == NULL) {
1838 return NULL;
1839 }
1840
1841 private = calloc(1, sizeof(stonith_private_t));
1842 if (private == NULL) {
1843 free(new_stonith);
1844 return NULL;
1845 }
1846 new_stonith->st_private = private;
1847
1848 private->stonith_op_callback_table = pcmk__intkey_table(stonith_destroy_op_callback);
1849 private->notify_list = NULL;
1850 private->notify_refcnt = 0;
1851 private->notify_deletes = FALSE;
1852
1853 new_stonith->call_id = 1;
1854 new_stonith->state = stonith_disconnected;
1855
1856 new_stonith->cmds = calloc(1, sizeof(stonith_api_operations_t));
1857 if (new_stonith->cmds == NULL) {
1858 free(new_stonith->st_private);
1859 free(new_stonith);
1860 return NULL;
1861 }
1862
1863/* *INDENT-OFF* */
1864 new_stonith->cmds->free = stonith_api_free;
1865 new_stonith->cmds->connect = stonith_api_signon;
1866 new_stonith->cmds->disconnect = stonith_api_signoff;
1867
1868 new_stonith->cmds->list = stonith_api_list;
1869 new_stonith->cmds->monitor = stonith_api_monitor;
1870 new_stonith->cmds->status = stonith_api_status;
1871 new_stonith->cmds->fence = stonith_api_fence;
1872 new_stonith->cmds->fence_with_delay = stonith_api_fence_with_delay;
1873 new_stonith->cmds->confirm = stonith_api_confirm;
1874 new_stonith->cmds->history = stonith_api_history;
1875
1876 new_stonith->cmds->list_agents = stonith_api_device_list;
1877 new_stonith->cmds->metadata = stonith_api_device_metadata;
1878
1879 new_stonith->cmds->query = stonith_api_query;
1880 new_stonith->cmds->remove_device = stonith_api_remove_device;
1881 new_stonith->cmds->register_device = stonith_api_register_device;
1882
1883 new_stonith->cmds->remove_level = stonith_api_remove_level;
1884 new_stonith->cmds->remove_level_full = stonith_api_remove_level_full;
1885 new_stonith->cmds->register_level = stonith_api_register_level;
1886 new_stonith->cmds->register_level_full = stonith_api_register_level_full;
1887
1888 new_stonith->cmds->remove_callback = stonith_api_del_callback;
1889 new_stonith->cmds->register_callback = stonith_api_add_callback;
1890 new_stonith->cmds->remove_notification = stonith_api_del_notification;
1891 new_stonith->cmds->register_notification = stonith_api_add_notification;
1892
1893 new_stonith->cmds->validate = stonith_api_validate;
1894/* *INDENT-ON* */
1895
1896 return new_stonith;
1897}
1898
1908int
1909stonith_api_connect_retry(stonith_t *st, const char *name, int max_attempts)
1910{
1911 int rc = -EINVAL; // if max_attempts is not positive
1912
1913 for (int attempt = 1; attempt <= max_attempts; attempt++) {
1914 rc = st->cmds->connect(st, name, NULL);
1915 if (rc == pcmk_ok) {
1916 return pcmk_ok;
1917 } else if (attempt < max_attempts) {
1918 crm_notice("Fencer connection attempt %d of %d failed (retrying in 2s): %s "
1919 CRM_XS " rc=%d",
1920 attempt, max_attempts, pcmk_strerror(rc), rc);
1921 sleep(2);
1922 }
1923 }
1924 crm_notice("Could not connect to fencer: %s " CRM_XS " rc=%d",
1925 pcmk_strerror(rc), rc);
1926 return rc;
1927}
1928
1930stonith_key_value_add(stonith_key_value_t * head, const char *key, const char *value)
1931{
1932 stonith_key_value_t *p, *end;
1933
1935 p->key = pcmk__str_copy(key);
1936 p->value = pcmk__str_copy(value);
1937
1938 end = head;
1939 while (end && end->next) {
1940 end = end->next;
1941 }
1942
1943 if (end) {
1944 end->next = p;
1945 } else {
1946 head = p;
1947 }
1948
1949 return head;
1950}
1951
1952void
1954{
1956
1957 while (head) {
1958 p = head->next;
1959 if (keys) {
1960 free(head->key);
1961 }
1962 if (values) {
1963 free(head->value);
1964 }
1965 free(head);
1966 head = p;
1967 }
1968}
1969
1970#define api_log_open() openlog("stonith-api", LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON)
1971#define api_log(level, fmt, args...) syslog(level, "%s: "fmt, __func__, args)
1972
1973int
1974stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off)
1975{
1976 int rc = pcmk_ok;
1978 const char *action = off? PCMK_ACTION_OFF : PCMK_ACTION_REBOOT;
1979
1980 api_log_open();
1981 if (st == NULL) {
1982 api_log(LOG_ERR, "API initialization failed, could not kick (%s) node %u/%s",
1983 action, nodeid, uname);
1984 return -EPROTO;
1985 }
1986
1987 rc = st->cmds->connect(st, "stonith-api", NULL);
1988 if (rc != pcmk_ok) {
1989 api_log(LOG_ERR, "Connection failed, could not kick (%s) node %u/%s : %s (%d)",
1990 action, nodeid, uname, pcmk_strerror(rc), rc);
1991 } else {
1992 char *name = (uname == NULL)? pcmk__itoa(nodeid) : strdup(uname);
1993 int opts = 0;
1994
1997 if ((uname == NULL) && (nodeid > 0)) {
1999 }
2000 rc = st->cmds->fence(st, opts, name, action, timeout, 0);
2001 free(name);
2002
2003 if (rc != pcmk_ok) {
2004 api_log(LOG_ERR, "Could not kick (%s) node %u/%s : %s (%d)",
2005 action, nodeid, uname, pcmk_strerror(rc), rc);
2006 } else {
2007 api_log(LOG_NOTICE, "Node %u/%s kicked: %s", nodeid, uname, action);
2008 }
2009 }
2010
2012 return rc;
2013}
2014
2015time_t
2016stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress)
2017{
2018 int rc = pcmk_ok;
2019 time_t when = 0;
2021 stonith_history_t *history = NULL, *hp = NULL;
2022
2023 if (st == NULL) {
2024 api_log(LOG_ERR, "Could not retrieve fence history for %u/%s: "
2025 "API initialization failed", nodeid, uname);
2026 return when;
2027 }
2028
2029 rc = st->cmds->connect(st, "stonith-api", NULL);
2030 if (rc != pcmk_ok) {
2031 api_log(LOG_NOTICE, "Connection failed: %s (%d)", pcmk_strerror(rc), rc);
2032 } else {
2033 int entries = 0;
2034 int progress = 0;
2035 int completed = 0;
2036 int opts = 0;
2037 char *name = (uname == NULL)? pcmk__itoa(nodeid) : strdup(uname);
2038
2040 if ((uname == NULL) && (nodeid > 0)) {
2042 }
2043 rc = st->cmds->history(st, opts, name, &history, 120);
2044 free(name);
2045
2046 for (hp = history; hp; hp = hp->next) {
2047 entries++;
2048 if (in_progress) {
2049 progress++;
2050 if (hp->state != st_done && hp->state != st_failed) {
2051 when = time(NULL);
2052 }
2053
2054 } else if (hp->state == st_done) {
2055 completed++;
2056 if (hp->completed > when) {
2057 when = hp->completed;
2058 }
2059 }
2060 }
2061
2062 stonith_history_free(history);
2063
2064 if(rc == pcmk_ok) {
2065 api_log(LOG_INFO, "Found %d entries for %u/%s: %d in progress, %d completed", entries, nodeid, uname, progress, completed);
2066 } else {
2067 api_log(LOG_ERR, "Could not retrieve fence history for %u/%s: %s (%d)", nodeid, uname, pcmk_strerror(rc), rc);
2068 }
2069 }
2070
2072
2073 if(when) {
2074 api_log(LOG_INFO, "Node %u/%s last kicked at: %ld", nodeid, uname, (long int)when);
2075 }
2076 return when;
2077}
2078
2079bool
2080stonith_agent_exists(const char *agent, int timeout)
2081{
2082 stonith_t *st = NULL;
2083 stonith_key_value_t *devices = NULL;
2084 stonith_key_value_t *dIter = NULL;
2085 bool rc = FALSE;
2086
2087 if (agent == NULL) {
2088 return rc;
2089 }
2090
2091 st = stonith_api_new();
2092 if (st == NULL) {
2093 crm_err("Could not list fence agents: API memory allocation failed");
2094 return FALSE;
2095 }
2096 st->cmds->list_agents(st, st_opt_sync_call, NULL, &devices, timeout == 0 ? 120 : timeout);
2097
2098 for (dIter = devices; dIter != NULL; dIter = dIter->next) {
2099 if (pcmk__str_eq(dIter->value, agent, pcmk__str_none)) {
2100 rc = TRUE;
2101 break;
2102 }
2103 }
2104
2105 stonith_key_value_freeall(devices, 1, 1);
2107 return rc;
2108}
2109
2110const char *
2112{
2113 if (action == NULL) {
2114 return "fencing";
2115 } else if (strcmp(action, PCMK_ACTION_ON) == 0) {
2116 return "unfencing";
2117 } else if (strcmp(action, PCMK_ACTION_OFF) == 0) {
2118 return "turning off";
2119 } else {
2120 return action;
2121 }
2122}
2123
2132static void
2133parse_list_line(const char *line, int len, GList **output)
2134{
2135 size_t i = 0;
2136 size_t entry_start = 0;
2137
2138 /* Skip complaints about additional parameters device doesn't understand
2139 *
2140 * @TODO Document or eliminate the implied restriction of target names
2141 */
2142 if (strstr(line, "invalid") || strstr(line, "variable")) {
2143 crm_debug("Skipping list output line: %s", line);
2144 return;
2145 }
2146
2147 // Process line content, character by character
2148 for (i = 0; i <= len; i++) {
2149
2150 if (isspace(line[i]) || (line[i] == ',') || (line[i] == ';')
2151 || (line[i] == '\0')) {
2152 // We've found a separator (i.e. the end of an entry)
2153
2154 int rc = 0;
2155 char *entry = NULL;
2156
2157 if (i == entry_start) {
2158 // Skip leading and sequential separators
2159 entry_start = i + 1;
2160 continue;
2161 }
2162
2163 entry = pcmk__assert_alloc(i - entry_start + 1, sizeof(char));
2164
2165 /* Read entry, stopping at first separator
2166 *
2167 * @TODO Document or eliminate these character restrictions
2168 */
2169 rc = sscanf(line + entry_start, "%[a-zA-Z0-9_-.]", entry);
2170 if (rc != 1) {
2171 crm_warn("Could not parse list output entry: %s "
2172 CRM_XS " entry_start=%d position=%d",
2173 line + entry_start, entry_start, i);
2174 free(entry);
2175
2176 } else if (pcmk__strcase_any_of(entry, PCMK_ACTION_ON,
2177 PCMK_ACTION_OFF, NULL)) {
2178 /* Some agents print the target status in the list output,
2179 * though none are known now (the separate list-status command
2180 * is used for this, but it can also print "UNKNOWN"). To handle
2181 * this possibility, skip such entries.
2182 *
2183 * @TODO Document or eliminate the implied restriction of target
2184 * names.
2185 */
2186 free(entry);
2187
2188 } else {
2189 // We have a valid entry
2190 *output = g_list_append(*output, entry);
2191 }
2192 entry_start = i + 1;
2193 }
2194 }
2195}
2196
2218GList *
2219stonith__parse_targets(const char *target_spec)
2220{
2221 GList *targets = NULL;
2222
2223 if (target_spec != NULL) {
2224 size_t out_len = strlen(target_spec);
2225 size_t line_start = 0; // Starting index of line being processed
2226
2227 for (size_t i = 0; i <= out_len; ++i) {
2228 if ((target_spec[i] == '\n') || (target_spec[i] == '\0')
2229 || ((target_spec[i] == '\\') && (target_spec[i + 1] == 'n'))) {
2230 // We've reached the end of one line of output
2231
2232 int len = i - line_start;
2233
2234 if (len > 0) {
2235 char *line = strndup(target_spec + line_start, len);
2236
2237 line[len] = '\0'; // Because it might be a newline
2238 parse_list_line(line, len, &targets);
2239 free(line);
2240 }
2241 if (target_spec[i] == '\\') {
2242 ++i; // backslash-n takes up two positions
2243 }
2244 line_start = i + 1;
2245 }
2246 }
2247 }
2248 return targets;
2249}
2250
2262const char *
2264 const stonith_history_t *top_history)
2265{
2266 const char *other = NULL;
2267
2268 for (const stonith_history_t *prev_hp = top_history;
2269 prev_hp != NULL; prev_hp = prev_hp->next) {
2270 if (prev_hp == event) {
2271 break;
2272 }
2273 if ((prev_hp->state == st_done) &&
2274 pcmk__str_eq(event->target, prev_hp->target, pcmk__str_casei) &&
2275 pcmk__str_eq(event->action, prev_hp->action, pcmk__str_none) &&
2276 ((event->completed < prev_hp->completed) ||
2277 ((event->completed == prev_hp->completed) && (event->completed_nsec < prev_hp->completed_nsec)))) {
2278
2279 if ((event->delegate == NULL)
2280 || pcmk__str_eq(event->delegate, prev_hp->delegate,
2281 pcmk__str_casei)) {
2282 // Prefer equivalent fencing by same executioner
2283 return prev_hp->delegate;
2284
2285 } else if (other == NULL) {
2286 // Otherwise remember first successful executioner
2287 other = (prev_hp->delegate == NULL)? "some node" : prev_hp->delegate;
2288 }
2289 }
2290 }
2291 return other;
2292}
2293
2304{
2305 stonith_history_t *new = NULL, *pending = NULL, *hp, *np, *tmp;
2306
2307 for (hp = history; hp; ) {
2308 tmp = hp->next;
2309 if ((hp->state == st_done) || (hp->state == st_failed)) {
2310 /* sort into new */
2311 if ((!new) || (hp->completed > new->completed) ||
2312 ((hp->completed == new->completed) && (hp->completed_nsec > new->completed_nsec))) {
2313 hp->next = new;
2314 new = hp;
2315 } else {
2316 np = new;
2317 do {
2318 if ((!np->next) || (hp->completed > np->next->completed) ||
2319 ((hp->completed == np->next->completed) && (hp->completed_nsec > np->next->completed_nsec))) {
2320 hp->next = np->next;
2321 np->next = hp;
2322 break;
2323 }
2324 np = np->next;
2325 } while (1);
2326 }
2327 } else {
2328 /* put into pending */
2329 hp->next = pending;
2330 pending = hp;
2331 }
2332 hp = tmp;
2333 }
2334
2335 /* pending actions don't have a completed-stamp so make them go front */
2336 if (pending) {
2337 stonith_history_t *last_pending = pending;
2338
2339 while (last_pending->next) {
2340 last_pending = last_pending->next;
2341 }
2342
2343 last_pending->next = new;
2344 new = pending;
2345 }
2346 return new;
2347}
2348
2356const char *
2358{
2359 switch (state) {
2360 case st_query: return "querying";
2361 case st_exec: return "executing";
2362 case st_done: return "completed";
2363 case st_duplicate: return "duplicate";
2364 case st_failed: return "failed";
2365 }
2366 return "unknown";
2367}
2368
2371 bool (*matching_fn)(stonith_history_t *, void *),
2372 void *user_data)
2373{
2374 for (stonith_history_t *hp = history; hp; hp = hp->next) {
2375 if (matching_fn(hp, user_data)) {
2376 return hp;
2377 }
2378 }
2379
2380 return NULL;
2381}
2382
2383bool
2385{
2386 return history->state != st_failed && history->state != st_done;
2387}
2388
2389bool
2391{
2392 return history->state == GPOINTER_TO_INT(user_data);
2393}
2394
2395bool
2397{
2398 return history->state != GPOINTER_TO_INT(user_data);
2399}
2400
2401void
2402stonith__device_parameter_flags(uint32_t *device_flags, const char *device_name,
2403 xmlNode *metadata)
2404{
2405 xmlXPathObjectPtr xpath = NULL;
2406 int max = 0;
2407 int lpc = 0;
2408
2409 CRM_CHECK((device_flags != NULL) && (metadata != NULL), return);
2410
2411 xpath = xpath_search(metadata, "//" PCMK_XE_PARAMETER);
2412 max = numXpathResults(xpath);
2413
2414 if (max <= 0) {
2415 freeXpathObject(xpath);
2416 return;
2417 }
2418
2419 for (lpc = 0; lpc < max; lpc++) {
2420 const char *parameter = NULL;
2421 xmlNode *match = getXpathResult(xpath, lpc);
2422
2423 CRM_LOG_ASSERT(match != NULL);
2424 if (match == NULL) {
2425 continue;
2426 }
2427
2428 parameter = crm_element_value(match, PCMK_XA_NAME);
2429
2430 if (pcmk__str_eq(parameter, "plug", pcmk__str_casei)) {
2431 stonith__set_device_flags(*device_flags, device_name,
2433
2434 } else if (pcmk__str_eq(parameter, "port", pcmk__str_casei)) {
2435 stonith__set_device_flags(*device_flags, device_name,
2437 }
2438 }
2439
2440 freeXpathObject(xpath);
2441}
2442
2462int
2463stonith__metadata_async(const char *agent, int timeout_sec,
2464 void (*callback)(int pid,
2466 void *user_data),
2467 void *user_data)
2468{
2469 switch (stonith_get_namespace(agent, NULL)) {
2470 case st_namespace_rhcs:
2471 {
2472 stonith_action_t *action = NULL;
2473 int rc = pcmk_ok;
2474
2476 NULL, 0, timeout_sec, NULL,
2477 NULL, NULL);
2478
2479 rc = stonith__execute_async(action, user_data, callback, NULL);
2480 if (rc != pcmk_ok) {
2481 callback(0, stonith__action_result(action), user_data);
2483 }
2484 return pcmk_legacy2rc(rc);
2485 }
2486
2487#if HAVE_STONITH_STONITH_H
2488 case st_namespace_lha:
2489 // LHA metadata is simply synthesized, so simulate async
2490 {
2493 .execution_status = PCMK_EXEC_DONE,
2494 .exit_reason = NULL,
2495 .action_stdout = NULL,
2496 .action_stderr = NULL,
2497 };
2498
2499 stonith__lha_metadata(agent, timeout_sec,
2501 callback(0, &result, user_data);
2503 return pcmk_rc_ok;
2504 }
2505#endif
2506
2507 default:
2508 {
2511 .execution_status = PCMK_EXEC_ERROR_HARD,
2512 .exit_reason = crm_strdup_printf("No such agent '%s'",
2513 agent),
2514 .action_stdout = NULL,
2515 .action_stderr = NULL,
2516 };
2517
2518 callback(0, &result, user_data);
2520 return ENOENT;
2521 }
2522 }
2523}
2524
2533int
2535{
2536 if ((data == NULL) || (data->opaque == NULL)) {
2537 return CRM_EX_ERROR;
2538 }
2539 return ((pcmk__action_result_t *) data->opaque)->exit_status;
2540}
2541
2550int
2552{
2553 if ((data == NULL) || (data->opaque == NULL)) {
2554 return PCMK_EXEC_UNKNOWN;
2555 }
2556 return ((pcmk__action_result_t *) data->opaque)->execution_status;
2557}
2558
2567const char *
2569{
2570 if ((data == NULL) || (data->opaque == NULL)) {
2571 return NULL;
2572 }
2573 return ((pcmk__action_result_t *) data->opaque)->exit_reason;
2574}
2575
2584int
2586{
2587 if ((event == NULL) || (event->opaque == NULL)) {
2588 return CRM_EX_ERROR;
2589 } else {
2590 struct event_private *event_private = event->opaque;
2591
2592 return event_private->result.exit_status;
2593 }
2594}
2595
2604int
2606{
2607 if ((event == NULL) || (event->opaque == NULL)) {
2608 return PCMK_EXEC_UNKNOWN;
2609 } else {
2610 struct event_private *event_private = event->opaque;
2611
2612 return event_private->result.execution_status;
2613 }
2614}
2615
2624const char *
2626{
2627 if ((event == NULL) || (event->opaque == NULL)) {
2628 return NULL;
2629 } else {
2630 struct event_private *event_private = event->opaque;
2631
2632 return event_private->result.exit_reason;
2633 }
2634}
2635
2646char *
2648{
2649 // Use somewhat readable defaults
2650 const char *origin = pcmk__s(event->client_origin, "a client");
2651 const char *origin_node = pcmk__s(event->origin, "a node");
2652 const char *executioner = pcmk__s(event->executioner, "the cluster");
2653 const char *device = pcmk__s(event->device, "unknown");
2654 const char *action = pcmk__s(event->action, event->operation);
2655 const char *target = pcmk__s(event->target, "no node");
2656 const char *reason = stonith__event_exit_reason(event);
2657 const char *status;
2658
2659 if (action == NULL) {
2660 action = "(unknown)";
2661 }
2662
2664 status = pcmk_exec_status_str(stonith__event_execution_status(event));
2665 } else if (stonith__event_exit_status(event) != CRM_EX_OK) {
2666 status = pcmk_exec_status_str(PCMK_EXEC_ERROR);
2667 } else {
2668 status = crm_exit_str(CRM_EX_OK);
2669 }
2670
2671 if (pcmk__str_eq(event->operation, PCMK__VALUE_ST_NOTIFY_HISTORY,
2672 pcmk__str_none)) {
2673 return crm_strdup_printf("Fencing history may have changed");
2674
2675 } else if (pcmk__str_eq(event->operation, STONITH_OP_DEVICE_ADD,
2676 pcmk__str_none)) {
2677 return crm_strdup_printf("A fencing device (%s) was added", device);
2678
2679 } else if (pcmk__str_eq(event->operation, STONITH_OP_DEVICE_DEL,
2680 pcmk__str_none)) {
2681 return crm_strdup_printf("A fencing device (%s) was removed", device);
2682
2683 } else if (pcmk__str_eq(event->operation, STONITH_OP_LEVEL_ADD,
2684 pcmk__str_none)) {
2685 return crm_strdup_printf("A fencing topology level (%s) was added",
2686 device);
2687
2688 } else if (pcmk__str_eq(event->operation, STONITH_OP_LEVEL_DEL,
2689 pcmk__str_none)) {
2690 return crm_strdup_printf("A fencing topology level (%s) was removed",
2691 device);
2692 }
2693
2694 // event->operation should be PCMK__VALUE_ST_NOTIFY_FENCE at this point
2695
2696 return crm_strdup_printf("Operation %s of %s by %s for %s@%s: %s%s%s%s (ref=%s)",
2697 action, target, executioner, origin, origin_node,
2698 status,
2699 ((reason == NULL)? "" : " ("), pcmk__s(reason, ""),
2700 ((reason == NULL)? "" : ")"),
2701 pcmk__s(event->id, "(none)"));
2702}
2703
2704
2705// Deprecated functions kept only for backward API compatibility
2706// LCOV_EXCL_START
2707
2708const char *get_stonith_provider(const char *agent, const char *provider);
2709
2710const char *
2711get_stonith_provider(const char *agent, const char *provider)
2712{
2713 return stonith_namespace2text(stonith_get_namespace(agent, provider));
2714}
2715
2716// LCOV_EXCL_STOP
2717// End deprecated API
#define PCMK_ACTION_STATUS
Definition actions.h:73
#define PCMK_ACTION_LIST
Definition actions.h:52
#define PCMK_ACTION_REBOOT
Definition actions.h:68
#define PCMK_ACTION_METADATA
Definition actions.h:57
#define PCMK_ACTION_MONITOR
Definition actions.h:60
#define PCMK_DEFAULT_METADATA_TIMEOUT_MS
Definition actions.h:42
#define PCMK_ACTION_ON
Definition actions.h:64
#define PCMK_ACTION_OFF
Definition actions.h:63
#define PCMK_STONITH_HOST_ARGUMENT
Definition agents.h:44
bool pcmk_stonith_param(const char *param)
Check whether a given stonith parameter is handled by Pacemaker.
Definition agents.c:175
const char * name
Definition cib.c:26
int pcmk__substitute_secrets(const char *rsc_id, GHashTable *params)
Definition cib_secrets.c:96
#define pcmk__assert_alloc(nmemb, size)
Definition internal.h:297
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
enum crm_ais_msg_types type
Definition cpg.c:3
char uname[MAX_NAME]
Definition cpg.c:5
char data[0]
Definition cpg.c:10
uint32_t id
Definition cpg.c:0
uint32_t pid
Definition cpg.c:1
A dumping ground.
#define CRM_OP_REGISTER
Definition crm.h:129
int stonith__legacy2status(int rc)
Definition st_actions.c:400
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:667
@ st_device_supports_parameter_port
Definition internal.h:25
@ st_device_supports_parameter_plug
Definition internal.h:24
#define STONITH_OP_QUERY
Definition internal.h:110
#define STONITH_OP_FENCE
Definition internal.h:111
void stonith__destroy_action(stonith_action_t *action)
Definition st_actions.c:215
#define STONITH_OP_DEVICE_ADD
Definition internal.h:113
stonith_action_t * stonith__action_create(const char *agent, const char *action_name, const char *target, uint32_t target_nodeid, int timeout_sec, GHashTable *device_args, GHashTable *port_map, const char *host_arg)
Definition st_actions.c:263
#define STONITH_OP_EXEC
Definition internal.h:108
#define stonith__set_device_flags(device_flags, device_id, flags_to_set)
Definition internal.h:29
#define STONITH_WATCHDOG_ID
Definition internal.h:125
#define STONITH_OP_LEVEL_ADD
Definition internal.h:116
#define STONITH_OP_FENCE_HISTORY
Definition internal.h:115
#define STONITH_OP_NOTIFY
Definition internal.h:118
pcmk__action_result_t * stonith__action_result(stonith_action_t *action)
Definition st_actions.c:240
struct stonith_action_s stonith_action_t
Definition internal.h:51
#define stonith__set_call_options(st_call_opts, call_for, flags_to_set)
Definition internal.h:36
void stonith__xe_get_result(const xmlNode *xml, pcmk__action_result_t *result)
Definition st_actions.c:490
#define STONITH_OP_LEVEL_DEL
Definition internal.h:117
int stonith__result2rc(const pcmk__action_result_t *result)
Definition st_actions.c:326
#define STONITH_OP_DEVICE_DEL
Definition internal.h:114
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:36
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)
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:164
@ crm_ipc_flags_none
Definition ipc.h:165
@ crm_ipc_client_response
Definition ipc.h:170
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:993
const char * crm_ipc_buffer(crm_ipc_t *client)
struct crm_ipc_s crm_ipc_t
Definition ipc.h:184
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:850
int pcmk__connect_generic_ipc(crm_ipc_t *ipc)
Definition ipc_client.c:896
int pcmk__ipc_fd(crm_ipc_t *ipc, int *fd)
#define pcmk__set_ipc_flags(ipc_flags, ipc_name, flags_to_set)
#define CRM_TRACE_INIT_DATA(name)
Definition logging.h:143
#define crm_info(fmt, args...)
Definition logging.h:397
#define crm_warn(fmt, args...)
Definition logging.h:392
#define CRM_XS
Definition logging.h:56
#define crm_log_xml_debug(xml, text)
Definition logging.h:409
#define CRM_LOG_ASSERT(expr)
Definition logging.h:228
#define crm_log_xml_err(xml, text)
Definition logging.h:405
#define crm_notice(fmt, args...)
Definition logging.h:395
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition logging.h:331
#define CRM_CHECK(expr, failure_action)
Definition logging.h:245
#define crm_debug(fmt, args...)
Definition logging.h:400
#define crm_err(fmt, args...)
Definition logging.h:389
#define LOG_NEVER
Definition logging.h:48
#define crm_log_xml_trace(xml, text)
Definition logging.h:410
#define crm_log_xml_warn(xml, text)
Definition logging.h:406
#define crm_trace(fmt, args...)
Definition logging.h:402
#define crm_log_xml_notice(xml, text)
Definition logging.h:407
Wrappers for and extensions to glib mainloop.
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
Definition mainloop.c:949
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:918
struct mainloop_io_s mainloop_io_t
Definition mainloop.h:35
#define G_PRIORITY_MEDIUM
Definition mainloop.h:192
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition mainloop.c:943
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:446
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition nvpair.c:482
void hash2field(gpointer key, gpointer value, gpointer user_data)
Set XML attribute based on hash table entry.
Definition nvpair.c:736
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
Definition nvpair.c:348
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition nvpair.c:674
int crm_element_value_ll(const xmlNode *data, const char *name, long long *dest)
Retrieve the long long integer value of an XML attribute.
Definition nvpair.c:514
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition nvpair.c:301
#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:32
int delay
Definition pcmk_fence.c:34
unsigned int tolerance
Definition pcmk_fence.c:33
stonith_t * st
Definition pcmk_fence.c:28
const char * action
Definition pcmk_fence.c:30
pcmk__action_result_t result
Definition pcmk_fence.c:35
const char * target
Definition pcmk_fence.c:29
#define ECOMM
Definition portability.h:86
#define ENOTUNIQ
Definition portability.h:81
const char * pcmk_strerror(int rc)
Definition results.c:149
#define CRM_ASSERT(expr)
Definition results.h:42
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition results.c:501
@ CRM_EX_NOSUCH
Requested item does not exist.
Definition results.h:291
@ CRM_EX_ERROR
Unspecified error.
Definition results.h:256
@ CRM_EX_OK
Success.
Definition results.h:255
@ pcmk_rc_ok
Definition results.h:162
#define pcmk_ok
Definition results.h:69
int pcmk_rc2legacy(int rc)
Definition results.c:546
const char * crm_exit_str(crm_exit_t exit_code)
Definition results.c:640
@ PCMK_EXEC_DONE
Action completed, result is known.
Definition results.h:333
@ PCMK_EXEC_ERROR
Execution failed, may be retried.
Definition results.h:337
@ PCMK_EXEC_TIMEOUT
Action did not complete in time.
Definition results.h:335
@ PCMK_EXEC_UNKNOWN
Used only to initialize variables.
Definition results.h:331
@ PCMK_EXEC_ERROR_HARD
Execution failed, do not retry on node.
Definition results.h:338
int pcmk_legacy2rc(int legacy_rc)
Definition results.c:559
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:976
#define PCMK__UNKNOWN_RESULT
void pcmk__reset_result(pcmk__action_result_t *result)
Definition results.c:1065
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:2463
void stonith_api_delete(stonith_t *stonith)
Definition st_client.c:1724
gboolean stonith__watchdog_fencing_enabled_for_node(const char *node)
Definition st_client.c:231
const char * stonith__exit_reason(const stonith_callback_data_t *data)
Definition st_client.c:2568
const char * stonith_namespace2text(enum stonith_namespace st_namespace)
Get agent namespace name.
Definition st_client.c:130
time_t stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress)
Definition st_client.c:2016
char * stonith__event_description(const stonith_event_t *event)
Definition st_client.c:2647
stonith_key_value_t * stonith_key_value_add(stonith_key_value_t *head, const char *key, const char *value)
Definition st_client.c:1930
xmlNode * create_device_registration_xml(const char *id, enum stonith_namespace namespace, const char *agent, const stonith_key_value_t *params, const char *rsc_provides)
Definition st_client.c:293
bool stonith__event_state_pending(stonith_history_t *history, void *user_data)
Definition st_client.c:2384
GList * stonith__parse_targets(const char *target_spec)
Definition st_client.c:2219
enum stonith_namespace stonith_get_namespace(const char *agent, const char *namespace_s)
Determine namespace of a fence agent.
Definition st_client.c:151
xmlNode * stonith_create_op(int call_id, const char *token, const char *op, xmlNode *data, int call_options)
Definition st_client.c:809
void stonith_history_free(stonith_history_t *history)
Definition st_client.c:762
bool stonith__event_state_neq(stonith_history_t *history, void *user_data)
Definition st_client.c:2396
enum stonith_namespace stonith_text2namespace(const char *namespace_s)
Get agent namespace by name.
Definition st_client.c:104
void stonith__device_parameter_flags(uint32_t *device_flags, const char *device_name, xmlNode *metadata)
Definition st_client.c:2402
bool stonith__event_state_eq(stonith_history_t *history, void *user_data)
Definition st_client.c:2390
const char * stonith_action_str(const char *action)
Turn fence action into a more readable string.
Definition st_client.c:2111
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:417
bool stonith_dispatch(stonith_t *st)
Definition st_client.c:1664
struct stonith_private_s stonith_private_t
int stonith_api_connect_retry(stonith_t *st, const char *name, int max_attempts)
Make a blocking connection attempt to the fencer.
Definition st_client.c:1909
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:2370
#define api_log(level, fmt, args...)
Definition st_client.c:1971
int stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off)
Definition st_client.c:1974
int stonith__exit_status(const stonith_callback_data_t *data)
Definition st_client.c:2534
const char * get_stonith_provider(const char *agent, const char *provider)
Definition st_client.c:2711
stonith_history_t * stonith__sort_history(stonith_history_t *history)
Definition st_client.c:2303
gboolean stonith__watchdog_fencing_enabled_for_node_api(stonith_t *st, const char *node)
Definition st_client.c:172
int stonith__execution_status(const stonith_callback_data_t *data)
Definition st_client.c:2551
int(* stonith_op_t)(const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **)
Definition st_client.c:82
int stonith__event_exit_status(const stonith_event_t *event)
Definition st_client.c:2585
int stonith__event_execution_status(const stonith_event_t *event)
Definition st_client.c:2605
stonith_t * stonith_api_new(void)
Definition st_client.c:1831
#define api_log_open()
Definition st_client.c:1970
const char * stonith__later_succeeded(const stonith_history_t *event, const stonith_history_t *top_history)
Definition st_client.c:2263
const char * stonith__event_exit_reason(const stonith_event_t *event)
Definition st_client.c:2625
struct stonith_notify_client_s stonith_notify_client_t
void stonith_key_value_freeall(stonith_key_value_t *head, int keys, int values)
Definition st_client.c:1953
struct stonith_callback_client_s stonith_callback_client_t
bool stonith_agent_exists(const char *agent, int timeout)
Definition st_client.c:2080
void stonith_dump_pending_callbacks(stonith_t *stonith)
Definition st_client.c:1368
const char * stonith_op_state_str(enum op_state state)
Return string equivalent of an operation state value.
Definition st_client.c:2357
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:290
bool stonith__agent_is_lha(const char *agent)
Definition st_lha.c:92
Fencing aka. STONITH.
@ st_opt_timeout_updates
Definition stonith-ng.h:56
@ st_opt_cs_nodeid
Definition stonith-ng.h:52
@ st_opt_discard_reply
Definition stonith-ng.h:48
@ st_opt_manual_ack
Definition stonith-ng.h:47
@ st_opt_allow_suicide
Definition stonith-ng.h:45
@ st_opt_report_only_success
Definition stonith-ng.h:58
@ st_opt_sync_call
Definition stonith-ng.h:53
stonith_namespace
Definition stonith-ng.h:76
@ st_namespace_invalid
Definition stonith-ng.h:77
@ st_namespace_rhcs
Definition stonith-ng.h:84
@ st_namespace_internal
Definition stonith-ng.h:79
@ st_namespace_any
Definition stonith-ng.h:78
@ st_namespace_lha
Definition stonith-ng.h:85
@ stonith_disconnected
Definition stonith-ng.h:39
@ stonith_connected_command
Definition stonith-ng.h:37
op_state
Definition stonith-ng.h:67
@ st_duplicate
Definition stonith-ng.h:71
@ st_query
Definition stonith-ng.h:68
@ st_failed
Definition stonith-ng.h:72
@ st_done
Definition stonith-ng.h:70
@ st_exec
Definition stonith-ng.h:69
void pcmk__insert_dup(GHashTable *table, const char *name, const char *value)
Definition strings.c:701
gboolean pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
Definition strings.c:981
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition strings.c:683
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:1026
@ 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:1050
#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:794
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Dispatch function for an IPC connection used as mainloop source.
Definition mainloop.h:94
enum pcmk_exec_status execution_status
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:537
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:233
int(* free)(stonith_t *st)
Destroy a fencer connection.
Definition stonith-ng.h:152
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:423
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:336
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:392
int(* connect)(stonith_t *st, const char *name, int *stonith_fd)
Connect to the local fencer.
Definition stonith-ng.h:164
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:203
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:218
int(* disconnect)(stonith_t *st)
Disconnect from the local stonith daemon.
Definition stonith-ng.h:173
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:290
int(* remove_callback)(stonith_t *stonith, int call_id, bool all_callbacks)
Unregister callbacks for asynchronous fencing results.
Definition stonith-ng.h:439
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:462
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:354
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:274
int(* confirm)(stonith_t *stonith, int call_options, const char *target)
Manually confirm that a node has been fenced.
Definition stonith-ng.h:367
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:319
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:489
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:514
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:304
int(* remove_notification)(stonith_t *stonith, const char *event)
Unregister callbacks for fence notifications.
Definition stonith-ng.h:404
int(* remove_device)(stonith_t *st, int options, const char *name)
Unregister a fence device with the local fencer.
Definition stonith-ng.h:185
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:380
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:253
char * client_origin
Definition stonith-ng.h:130
struct stonith_history_s * next
Definition stonith-ng.h:107
struct stonith_key_value_s * next
Definition stonith-ng.h:96
enum stonith_state state
Definition stonith-ng.h:545
void * st_private
Definition stonith-ng.h:549
stonith_api_operations_t * cmds
Definition stonith-ng.h:551
guint ref
Definition internal.h:114
stonith_t * stonith
Definition st_client.c:79
Wrappers for and extensions to libxml2.
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition xpath.c:189
xmlNode * getXpathResult(xmlXPathObjectPtr xpathObj, int index)
Definition xpath.c:58
void freeXpathObject(xmlXPathObjectPtr xpathObj)
Definition xpath.c:39
void free_xml(xmlNode *child)
Definition xml.c:867
xmlXPathObjectPtr xpath_search(const xmlNode *xml_top, const char *path)
Definition xpath.c:139
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition xml.c:883
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition xml.c:440
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition xml.c:720
xmlNode * pcmk__xml_parse(const char *input)
Definition xml_io.c:244
#define PCMK_XA_TARGET_PATTERN
Definition xml_names.h:416
#define PCMK_XE_FENCING_LEVEL
Definition xml_names.h:114
#define PCMK_XA_AGENT
Definition xml_names.h:229
#define PCMK_XA_TARGET
Definition xml_names.h:413
#define PCMK_XA_ID
Definition xml_names.h:296
#define PCMK_XA_TARGET_VALUE
Definition xml_names.h:418
#define PCMK_XA_EXIT_REASON
Definition xml_names.h:269
#define PCMK_XA_TARGET_ATTRIBUTE
Definition xml_names.h:414
#define PCMK_XA_NAME
Definition xml_names.h:325
#define PCMK_XE_PARAMETER
Definition xml_names.h:155
#define PCMK_XA_INDEX
Definition xml_names.h:300
#define PCMK_XA_DEVICES
Definition xml_names.h:259
#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