pacemaker 2.1.5-a3f44794f94
Scalable High-Availability cluster resource manager
st_client.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2022 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/msg_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
232{
234}
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 = create_xml_node(NULL, "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{
298 xmlNode *data = create_xml_node(NULL, F_STONITH_DEVICE);
299 xmlNode *args = create_xml_node(data, XML_TAG_ATTRS);
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
313 crm_xml_add(data, "agent", agent);
314 if ((namespace != st_namespace_any) && (namespace != st_namespace_invalid)) {
315 crm_xml_add(data, "namespace", stonith_namespace2text(namespace));
316 }
317 if (rsc_provides) {
318 crm_xml_add(data, "rsc_provides", rsc_provides);
319 }
320
321 for (; params; params = params->next) {
322 hash2field((gpointer) params->key, (gpointer) params->value, args);
323 }
324
325 return data;
326}
327
328static int
329stonith_api_register_device(stonith_t *st, int call_options,
330 const char *id, const char *namespace,
331 const char *agent,
332 const stonith_key_value_t *params)
333{
334 int rc = 0;
335 xmlNode *data = NULL;
336
338 agent, params, NULL);
339
340 rc = stonith_send_command(st, STONITH_OP_DEVICE_ADD, data, NULL, call_options, 0);
341 free_xml(data);
342
343 return rc;
344}
345
346static int
347stonith_api_remove_device(stonith_t * st, int call_options, const char *name)
348{
349 int rc = 0;
350 xmlNode *data = NULL;
351
355 rc = stonith_send_command(st, STONITH_OP_DEVICE_DEL, data, NULL, call_options, 0);
356 free_xml(data);
357
358 return rc;
359}
360
361static int
362stonith_api_remove_level_full(stonith_t *st, int options,
363 const char *node, const char *pattern,
364 const char *attr, const char *value, int level)
365{
366 int rc = 0;
367 xmlNode *data = NULL;
368
369 CRM_CHECK(node || pattern || (attr && value), return -EINVAL);
370
373
374 if (node) {
376
377 } else if (pattern) {
379
380 } else {
383 }
384
386 rc = stonith_send_command(st, STONITH_OP_LEVEL_DEL, data, NULL, options, 0);
387 free_xml(data);
388
389 return rc;
390}
391
392static int
393stonith_api_remove_level(stonith_t * st, int options, const char *node, int level)
394{
395 return stonith_api_remove_level_full(st, options, node,
396 NULL, NULL, NULL, level);
397}
398
414xmlNode *
415create_level_registration_xml(const char *node, const char *pattern,
416 const char *attr, const char *value,
417 int level, const stonith_key_value_t *device_list)
418{
419 GString *list = NULL;
420 xmlNode *data;
421
422 CRM_CHECK(node || pattern || (attr && value), return NULL);
423
425 CRM_CHECK(data, return NULL);
426
430
431 if (node) {
433
434 } else if (pattern) {
436
437 } else {
440 }
441
442 for (; device_list; device_list = device_list->next) {
443 pcmk__add_separated_word(&list, 1024, device_list->value, ",");
444 }
445
446 if (list != NULL) {
447 crm_xml_add(data, XML_ATTR_STONITH_DEVICES, (const char *) list->str);
448 g_string_free(list, TRUE);
449 }
450 return data;
451}
452
453static int
454stonith_api_register_level_full(stonith_t *st, int options, const char *node,
455 const char *pattern, const char *attr,
456 const char *value, int level,
457 const stonith_key_value_t *device_list)
458{
459 int rc = 0;
460 xmlNode *data = create_level_registration_xml(node, pattern, attr, value,
461 level, device_list);
462 CRM_CHECK(data != NULL, return -EINVAL);
463
464 rc = stonith_send_command(st, STONITH_OP_LEVEL_ADD, data, NULL, options, 0);
465 free_xml(data);
466
467 return rc;
468}
469
470static int
471stonith_api_register_level(stonith_t * st, int options, const char *node, int level,
472 const stonith_key_value_t * device_list)
473{
474 return stonith_api_register_level_full(st, options, node, NULL, NULL, NULL,
475 level, device_list);
476}
477
478static int
479stonith_api_device_list(stonith_t * stonith, int call_options, const char *namespace,
480 stonith_key_value_t ** devices, int timeout)
481{
482 int count = 0;
483 enum stonith_namespace ns = stonith_text2namespace(namespace);
484
485 if (devices == NULL) {
486 crm_err("Parameter error: stonith_api_device_list");
487 return -EFAULT;
488 }
489
490#if HAVE_STONITH_STONITH_H
491 // Include Linux-HA agents if requested
492 if ((ns == st_namespace_any) || (ns == st_namespace_lha)) {
493 count += stonith__list_lha_agents(devices);
494 }
495#endif
496
497 // Include Red Hat agents if requested
498 if ((ns == st_namespace_any) || (ns == st_namespace_rhcs)) {
499 count += stonith__list_rhcs_agents(devices);
500 }
501
502 return count;
503}
504
505// See stonith_api_operations_t:metadata() documentation
506static int
507stonith_api_device_metadata(stonith_t *stonith, int call_options,
508 const char *agent, const char *namespace,
509 char **output, int timeout_sec)
510{
511 /* By executing meta-data directly, we can get it from stonith_admin when
512 * the cluster is not running, which is important for higher-level tools.
513 */
514
515 enum stonith_namespace ns = stonith_get_namespace(agent, namespace);
516
517 if (timeout_sec <= 0) {
518 timeout_sec = CRMD_METADATA_CALL_TIMEOUT;
519 }
520
521 crm_trace("Looking up metadata for %s agent %s",
522 stonith_namespace2text(ns), agent);
523
524 switch (ns) {
526 return stonith__rhcs_metadata(agent, timeout_sec, output);
527
528#if HAVE_STONITH_STONITH_H
529 case st_namespace_lha:
530 return stonith__lha_metadata(agent, timeout_sec, output);
531#endif
532
533 default:
534 crm_err("Can't get fence agent '%s' meta-data: No such agent",
535 agent);
536 break;
537 }
538 return -ENODEV;
539}
540
541static int
542stonith_api_query(stonith_t * stonith, int call_options, const char *target,
543 stonith_key_value_t ** devices, int timeout)
544{
545 int rc = 0, lpc = 0, max = 0;
546
547 xmlNode *data = NULL;
548 xmlNode *output = NULL;
549 xmlXPathObjectPtr xpathObj = NULL;
550
551 CRM_CHECK(devices != NULL, return -EINVAL);
552
557 rc = stonith_send_command(stonith, STONITH_OP_QUERY, data, &output, call_options, timeout);
558
559 if (rc < 0) {
560 return rc;
561 }
562
563 xpathObj = xpath_search(output, "//@agent");
564 if (xpathObj) {
565 max = numXpathResults(xpathObj);
566
567 for (lpc = 0; lpc < max; lpc++) {
568 xmlNode *match = getXpathResult(xpathObj, lpc);
569
570 CRM_LOG_ASSERT(match != NULL);
571 if(match != NULL) {
572 xmlChar *match_path = xmlGetNodePath(match);
573
574 crm_info("%s[%d] = %s", "//@agent", lpc, match_path);
575 free(match_path);
576 *devices = stonith_key_value_add(*devices, NULL, crm_element_value(match, XML_ATTR_ID));
577 }
578 }
579
580 freeXpathObject(xpathObj);
581 }
582
583 free_xml(output);
584 free_xml(data);
585 return max;
586}
587
600static int
601stonith_api_call(stonith_t *stonith, int call_options, const char *id,
602 const char *action, const char *target, int timeout_sec,
603 xmlNode **output)
604{
605 int rc = 0;
606 xmlNode *data = NULL;
607
613
614 rc = stonith_send_command(stonith, STONITH_OP_EXEC, data, output,
615 call_options, timeout_sec);
616 free_xml(data);
617
618 return rc;
619}
620
621static int
622stonith_api_list(stonith_t * stonith, int call_options, const char *id, char **list_info,
623 int timeout)
624{
625 int rc;
626 xmlNode *output = NULL;
627
628 rc = stonith_api_call(stonith, call_options, id, "list", NULL, timeout, &output);
629
630 if (output && list_info) {
631 const char *list_str;
632
633 list_str = crm_element_value(output, F_STONITH_OUTPUT);
634
635 if (list_str) {
636 *list_info = strdup(list_str);
637 }
638 }
639
640 if (output) {
641 free_xml(output);
642 }
643
644 return rc;
645}
646
647static int
648stonith_api_monitor(stonith_t * stonith, int call_options, const char *id, int timeout)
649{
650 return stonith_api_call(stonith, call_options, id, "monitor", NULL, timeout, NULL);
651}
652
653static int
654stonith_api_status(stonith_t * stonith, int call_options, const char *id, const char *port,
655 int timeout)
656{
657 return stonith_api_call(stonith, call_options, id, "status", port, timeout, NULL);
658}
659
660static int
661stonith_api_fence_with_delay(stonith_t * stonith, int call_options, const char *node,
662 const char *action, int timeout, int tolerance, int delay)
663{
664 int rc = 0;
665 xmlNode *data = NULL;
666
667 data = create_xml_node(NULL, __func__);
673
674 rc = stonith_send_command(stonith, STONITH_OP_FENCE, data, NULL, call_options, timeout);
675 free_xml(data);
676
677 return rc;
678}
679
680static int
681stonith_api_fence(stonith_t * stonith, int call_options, const char *node, const char *action,
682 int timeout, int tolerance)
683{
684 return stonith_api_fence_with_delay(stonith, call_options, node, action,
685 timeout, tolerance, 0);
686}
687
688static int
689stonith_api_confirm(stonith_t * stonith, int call_options, const char *target)
690{
692 return stonith_api_fence(stonith, call_options, target, "off", 0, 0);
693}
694
695static int
696stonith_api_history(stonith_t * stonith, int call_options, const char *node,
697 stonith_history_t ** history, int timeout)
698{
699 int rc = 0;
700 xmlNode *data = NULL;
701 xmlNode *output = NULL;
702 stonith_history_t *last = NULL;
703
704 *history = NULL;
705
706 if (node) {
707 data = create_xml_node(NULL, __func__);
709 }
710
711 stonith__set_call_options(call_options, node, st_opt_sync_call);
712 rc = stonith_send_command(stonith, STONITH_OP_FENCE_HISTORY, data, &output,
713 call_options, timeout);
714 free_xml(data);
715
716 if (rc == 0) {
717 xmlNode *op = NULL;
718 xmlNode *reply = get_xpath_object("//" F_STONITH_HISTORY_LIST, output,
719 LOG_NEVER);
720
721 for (op = pcmk__xml_first_child(reply); op != NULL;
722 op = pcmk__xml_next(op)) {
724 long long completed;
725 long long completed_nsec = 0L;
726
727 kvp = calloc(1, sizeof(stonith_history_t));
733 crm_element_value_ll(op, F_STONITH_DATE, &completed);
734 kvp->completed = (time_t) completed;
735 crm_element_value_ll(op, F_STONITH_DATE_NSEC, &completed_nsec);
736 kvp->completed_nsec = completed_nsec;
740
741 if (last) {
742 last->next = kvp;
743 } else {
744 *history = kvp;
745 }
746 last = kvp;
747 }
748 }
749
750 free_xml(output);
751
752 return rc;
753}
754
756{
757 stonith_history_t *hp, *hp_old;
758
759 for (hp = history; hp; hp_old = hp, hp = hp->next, free(hp_old)) {
760 free(hp->target);
761 free(hp->action);
762 free(hp->origin);
763 free(hp->delegate);
764 free(hp->client);
765 free(hp->exit_reason);
766 }
767}
768
769static gint
770stonithlib_GCompareFunc(gconstpointer a, gconstpointer b)
771{
772 int rc = 0;
773 const stonith_notify_client_t *a_client = a;
774 const stonith_notify_client_t *b_client = b;
775
776 if (a_client->delete || b_client->delete) {
777 /* make entries marked for deletion not findable */
778 return -1;
779 }
780 CRM_CHECK(a_client->event != NULL && b_client->event != NULL, return 0);
781 rc = strcmp(a_client->event, b_client->event);
782 if (rc == 0) {
783 if (a_client->notify == NULL || b_client->notify == NULL) {
784 return 0;
785
786 } else if (a_client->notify == b_client->notify) {
787 return 0;
788
789 } else if (((long)a_client->notify) < ((long)b_client->notify)) {
790 crm_err("callbacks for %s are not equal: %p vs. %p",
791 a_client->event, a_client->notify, b_client->notify);
792 return -1;
793 }
794 crm_err("callbacks for %s are not equal: %p vs. %p",
795 a_client->event, a_client->notify, b_client->notify);
796 return 1;
797 }
798 return rc;
799}
800
801xmlNode *
802stonith_create_op(int call_id, const char *token, const char *op, xmlNode * data, int call_options)
803{
804 xmlNode *op_msg = create_xml_node(NULL, "stonith_command");
805
806 CRM_CHECK(op_msg != NULL, return NULL);
807 CRM_CHECK(token != NULL, return NULL);
808
809 crm_xml_add(op_msg, F_XML_TAGNAME, "stonith_command");
810
813 crm_xml_add(op_msg, F_STONITH_OPERATION, op);
814 crm_xml_add_int(op_msg, F_STONITH_CALLID, call_id);
815 crm_trace("Sending call options: %.8lx, %d", (long)call_options, call_options);
816 crm_xml_add_int(op_msg, F_STONITH_CALLOPTS, call_options);
817
818 if (data != NULL) {
820 }
821
822 return op_msg;
823}
824
825static void
826stonith_destroy_op_callback(gpointer data)
827{
829
830 if (blob->timer && blob->timer->ref > 0) {
831 g_source_remove(blob->timer->ref);
832 }
833 free(blob->timer);
834 free(blob);
835}
836
837static int
838stonith_api_signoff(stonith_t * stonith)
839{
840 stonith_private_t *native = stonith->st_private;
841
842 crm_debug("Disconnecting from the fencer");
843
844 if (native->source != NULL) {
845 /* Attached to mainloop */
846 mainloop_del_ipc_client(native->source);
847 native->source = NULL;
848 native->ipc = NULL;
849
850 } else if (native->ipc) {
851 /* Not attached to mainloop */
852 crm_ipc_t *ipc = native->ipc;
853
854 native->ipc = NULL;
855 crm_ipc_close(ipc);
856 crm_ipc_destroy(ipc);
857 }
858
859 free(native->token); native->token = NULL;
860 stonith->state = stonith_disconnected;
861 return pcmk_ok;
862}
863
864static int
865stonith_api_del_callback(stonith_t * stonith, int call_id, bool all_callbacks)
866{
867 stonith_private_t *private = stonith->st_private;
868
869 if (all_callbacks) {
870 private->op_callback = NULL;
871 g_hash_table_destroy(private->stonith_op_callback_table);
872 private->stonith_op_callback_table = pcmk__intkey_table(stonith_destroy_op_callback);
873
874 } else if (call_id == 0) {
875 private->op_callback = NULL;
876
877 } else {
878 pcmk__intkey_table_remove(private->stonith_op_callback_table, call_id);
879 }
880 return pcmk_ok;
881}
882
894static void
895invoke_fence_action_callback(stonith_t *st, int call_id,
897 void *userdata,
898 void (*callback) (stonith_t *st,
900{
902
903 data.call_id = call_id;
905 data.userdata = userdata;
906 data.opaque = (void *) result;
907
908 callback(st, &data);
909}
910
922static void
923invoke_registered_callbacks(stonith_t *stonith, xmlNode *msg, int call_id)
924{
925 stonith_private_t *private = NULL;
926 stonith_callback_client_t *cb_info = NULL;
928
929 CRM_CHECK(stonith != NULL, return);
930 CRM_CHECK(stonith->st_private != NULL, return);
931
932 private = stonith->st_private;
933
934 if (msg == NULL) {
935 // Fencer didn't reply in time
937 "Fencer accepted request but did not reply in time");
938 CRM_LOG_ASSERT(call_id > 0);
939
940 } else {
941 // We have the fencer reply
942 if ((crm_element_value_int(msg, F_STONITH_CALLID, &call_id) != 0)
943 || (call_id <= 0)) {
944 crm_log_xml_warn(msg, "Bad fencer reply");
945 }
947 }
948
949 if (call_id > 0) {
950 cb_info = pcmk__intkey_table_lookup(private->stonith_op_callback_table,
951 call_id);
952 }
953
954 if ((cb_info != NULL) && (cb_info->callback != NULL)
955 && (pcmk__result_ok(&result) || !(cb_info->only_success))) {
956 crm_trace("Invoking callback %s for call %d",
957 pcmk__s(cb_info->id, "without ID"), call_id);
958 invoke_fence_action_callback(stonith, call_id, &result,
959 cb_info->user_data, cb_info->callback);
960
961 } else if ((private->op_callback == NULL) && !pcmk__result_ok(&result)) {
962 crm_warn("Fencing action without registered callback failed: %d (%s%s%s)",
964 pcmk_exec_status_str(result.execution_status),
965 ((result.exit_reason == NULL)? "" : ": "),
966 ((result.exit_reason == NULL)? "" : result.exit_reason));
967 crm_log_xml_debug(msg, "Failed fence update");
968 }
969
970 if (private->op_callback != NULL) {
971 crm_trace("Invoking global callback for call %d", call_id);
972 invoke_fence_action_callback(stonith, call_id, &result, NULL,
973 private->op_callback);
974 }
975
976 if (cb_info != NULL) {
977 stonith_api_del_callback(stonith, call_id, FALSE);
978 }
980}
981
982static gboolean
983stonith_async_timeout_handler(gpointer data)
984{
985 struct timer_rec_s *timer = data;
986
987 crm_err("Async call %d timed out after %dms", timer->call_id, timer->timeout);
988 invoke_registered_callbacks(timer->stonith, NULL, timer->call_id);
989
990 /* Always return TRUE, never remove the handler
991 * We do that in stonith_del_callback()
992 */
993 return TRUE;
994}
995
996static void
997set_callback_timeout(stonith_callback_client_t * callback, stonith_t * stonith, int call_id,
998 int timeout)
999{
1000 struct timer_rec_s *async_timer = callback->timer;
1001
1002 if (timeout <= 0) {
1003 return;
1004 }
1005
1006 if (!async_timer) {
1007 async_timer = calloc(1, sizeof(struct timer_rec_s));
1008 callback->timer = async_timer;
1009 }
1010
1011 async_timer->stonith = stonith;
1012 async_timer->call_id = call_id;
1013 /* Allow a fair bit of grace to allow the server to tell us of a timeout
1014 * This is only a fallback
1015 */
1016 async_timer->timeout = (timeout + 60) * 1000;
1017 if (async_timer->ref) {
1018 g_source_remove(async_timer->ref);
1019 }
1020 async_timer->ref =
1021 g_timeout_add(async_timer->timeout, stonith_async_timeout_handler, async_timer);
1022}
1023
1024static void
1025update_callback_timeout(int call_id, int timeout, stonith_t * st)
1026{
1027 stonith_callback_client_t *callback = NULL;
1028 stonith_private_t *private = st->st_private;
1029
1030 callback = pcmk__intkey_table_lookup(private->stonith_op_callback_table,
1031 call_id);
1032 if (!callback || !callback->allow_timeout_updates) {
1033 return;
1034 }
1035
1036 set_callback_timeout(callback, st, call_id, timeout);
1037}
1038
1039static int
1040stonith_dispatch_internal(const char *buffer, ssize_t length, gpointer userdata)
1041{
1042 const char *type = NULL;
1043 struct notify_blob_s blob;
1044
1045 stonith_t *st = userdata;
1046 stonith_private_t *private = NULL;
1047
1048 CRM_ASSERT(st != NULL);
1049 private = st->st_private;
1050
1051 blob.stonith = st;
1052 blob.xml = string2xml(buffer);
1053 if (blob.xml == NULL) {
1054 crm_warn("Received malformed message from fencer: %s", buffer);
1055 return 0;
1056 }
1057
1058 /* do callbacks */
1059 type = crm_element_value(blob.xml, F_TYPE);
1060 crm_trace("Activating %s callbacks...", type);
1061
1062 if (pcmk__str_eq(type, T_STONITH_NG, pcmk__str_none)) {
1063 invoke_registered_callbacks(st, blob.xml, 0);
1064
1065 } else if (pcmk__str_eq(type, T_STONITH_NOTIFY, pcmk__str_none)) {
1066 foreach_notify_entry(private, stonith_send_notification, &blob);
1067 } else if (pcmk__str_eq(type, T_STONITH_TIMEOUT_VALUE, pcmk__str_none)) {
1068 int call_id = 0;
1069 int timeout = 0;
1070
1072 crm_element_value_int(blob.xml, F_STONITH_CALLID, &call_id);
1073
1074 update_callback_timeout(call_id, timeout, st);
1075 } else {
1076 crm_err("Unknown message type: %s", type);
1077 crm_log_xml_warn(blob.xml, "BadReply");
1078 }
1079
1080 free_xml(blob.xml);
1081 return 1;
1082}
1083
1084static int
1085stonith_api_signon(stonith_t * stonith, const char *name, int *stonith_fd)
1086{
1087 int rc = pcmk_ok;
1088 stonith_private_t *native = NULL;
1089 const char *display_name = name? name : "client";
1090
1091 struct ipc_client_callbacks st_callbacks = {
1092 .dispatch = stonith_dispatch_internal,
1093 .destroy = stonith_connection_destroy
1094 };
1095
1096 CRM_CHECK(stonith != NULL, return -EINVAL);
1097
1098 native = stonith->st_private;
1099 CRM_ASSERT(native != NULL);
1100
1101 crm_debug("Attempting fencer connection by %s with%s mainloop",
1102 display_name, (stonith_fd? "out" : ""));
1103
1105 if (stonith_fd) {
1106 /* No mainloop */
1107 native->ipc = crm_ipc_new("stonith-ng", 0);
1108
1109 if (native->ipc && crm_ipc_connect(native->ipc)) {
1110 *stonith_fd = crm_ipc_get_fd(native->ipc);
1111 } else if (native->ipc) {
1112 crm_ipc_close(native->ipc);
1113 crm_ipc_destroy(native->ipc);
1114 native->ipc = NULL;
1115 }
1116
1117 } else {
1118 /* With mainloop */
1119 native->source =
1120 mainloop_add_ipc_client("stonith-ng", G_PRIORITY_MEDIUM, 0, stonith, &st_callbacks);
1121 native->ipc = mainloop_get_ipc_client(native->source);
1122 }
1123
1124 if (native->ipc == NULL) {
1125 rc = -ENOTCONN;
1126 } else {
1127 xmlNode *reply = NULL;
1128 xmlNode *hello = create_xml_node(NULL, "stonith_command");
1129
1133 rc = crm_ipc_send(native->ipc, hello, crm_ipc_client_response, -1, &reply);
1134
1135 if (rc < 0) {
1136 crm_debug("Couldn't register with the fencer: %s "
1137 CRM_XS " rc=%d", pcmk_strerror(rc), rc);
1138 rc = -ECOMM;
1139
1140 } else if (reply == NULL) {
1141 crm_debug("Couldn't register with the fencer: no reply");
1142 rc = -EPROTO;
1143
1144 } else {
1145 const char *msg_type = crm_element_value(reply, F_STONITH_OPERATION);
1146
1147 native->token = crm_element_value_copy(reply, F_STONITH_CLIENTID);
1148 if (!pcmk__str_eq(msg_type, CRM_OP_REGISTER, pcmk__str_none)) {
1149 crm_debug("Couldn't register with the fencer: invalid reply type '%s'",
1150 (msg_type? msg_type : "(missing)"));
1151 crm_log_xml_debug(reply, "Invalid fencer reply");
1152 rc = -EPROTO;
1153
1154 } else if (native->token == NULL) {
1155 crm_debug("Couldn't register with the fencer: no token in reply");
1156 crm_log_xml_debug(reply, "Invalid fencer reply");
1157 rc = -EPROTO;
1158
1159 } else {
1160 crm_debug("Connection to fencer by %s succeeded (registration token: %s)",
1161 display_name, native->token);
1162 rc = pcmk_ok;
1163 }
1164 }
1165
1166 free_xml(reply);
1167 free_xml(hello);
1168 }
1169
1170 if (rc != pcmk_ok) {
1171 crm_debug("Connection attempt to fencer by %s failed: %s "
1172 CRM_XS " rc=%d", display_name, pcmk_strerror(rc), rc);
1173 stonith->cmds->disconnect(stonith);
1174 }
1175 return rc;
1176}
1177
1178static int
1179stonith_set_notification(stonith_t * stonith, const char *callback, int enabled)
1180{
1181 int rc = pcmk_ok;
1182 xmlNode *notify_msg = create_xml_node(NULL, __func__);
1183 stonith_private_t *native = stonith->st_private;
1184
1185 if (stonith->state != stonith_disconnected) {
1186
1188 if (enabled) {
1189 crm_xml_add(notify_msg, F_STONITH_NOTIFY_ACTIVATE, callback);
1190 } else {
1191 crm_xml_add(notify_msg, F_STONITH_NOTIFY_DEACTIVATE, callback);
1192 }
1193
1194 rc = crm_ipc_send(native->ipc, notify_msg, crm_ipc_client_response, -1, NULL);
1195 if (rc < 0) {
1196 crm_perror(LOG_DEBUG, "Couldn't register for fencing notifications: %d", rc);
1197 rc = -ECOMM;
1198 } else {
1199 rc = pcmk_ok;
1200 }
1201 }
1202
1203 free_xml(notify_msg);
1204 return rc;
1205}
1206
1207static int
1208stonith_api_add_notification(stonith_t * stonith, const char *event,
1209 void (*callback) (stonith_t * stonith, stonith_event_t * e))
1210{
1211 GList *list_item = NULL;
1212 stonith_notify_client_t *new_client = NULL;
1213 stonith_private_t *private = NULL;
1214
1215 private = stonith->st_private;
1216 crm_trace("Adding callback for %s events (%d)", event, g_list_length(private->notify_list));
1217
1218 new_client = calloc(1, sizeof(stonith_notify_client_t));
1219 new_client->event = event;
1220 new_client->notify = callback;
1221
1222 list_item = g_list_find_custom(private->notify_list, new_client, stonithlib_GCompareFunc);
1223
1224 if (list_item != NULL) {
1225 crm_warn("Callback already present");
1226 free(new_client);
1227 return -ENOTUNIQ;
1228
1229 } else {
1230 private->notify_list = g_list_append(private->notify_list, new_client);
1231
1232 stonith_set_notification(stonith, event, 1);
1233
1234 crm_trace("Callback added (%d)", g_list_length(private->notify_list));
1235 }
1236 return pcmk_ok;
1237}
1238
1239static void
1240del_notify_entry(gpointer data, gpointer user_data)
1241{
1243 stonith_t * stonith = user_data;
1244
1245 if (!entry->delete) {
1246 crm_debug("Removing callback for %s events", entry->event);
1247 stonith_api_del_notification(stonith, entry->event);
1248 }
1249}
1250
1251static int
1252stonith_api_del_notification(stonith_t * stonith, const char *event)
1253{
1254 GList *list_item = NULL;
1255 stonith_notify_client_t *new_client = NULL;
1256 stonith_private_t *private = stonith->st_private;
1257
1258 if (event == NULL) {
1259 foreach_notify_entry(private, del_notify_entry, stonith);
1260 crm_trace("Removed callback");
1261
1262 return pcmk_ok;
1263 }
1264
1265 crm_debug("Removing callback for %s events", event);
1266
1267 new_client = calloc(1, sizeof(stonith_notify_client_t));
1268 new_client->event = event;
1269 new_client->notify = NULL;
1270
1271 list_item = g_list_find_custom(private->notify_list, new_client, stonithlib_GCompareFunc);
1272
1273 stonith_set_notification(stonith, event, 0);
1274
1275 if (list_item != NULL) {
1276 stonith_notify_client_t *list_client = list_item->data;
1277
1278 if (private->notify_refcnt) {
1279 list_client->delete = TRUE;
1280 private->notify_deletes = TRUE;
1281 } else {
1282 private->notify_list = g_list_remove(private->notify_list, list_client);
1283 free(list_client);
1284 }
1285
1286 crm_trace("Removed callback");
1287
1288 } else {
1289 crm_trace("Callback not present");
1290 }
1291 free(new_client);
1292 return pcmk_ok;
1293}
1294
1295static int
1296stonith_api_add_callback(stonith_t * stonith, int call_id, int timeout, int options,
1297 void *user_data, const char *callback_name,
1298 void (*callback) (stonith_t * st, stonith_callback_data_t * data))
1299{
1300 stonith_callback_client_t *blob = NULL;
1301 stonith_private_t *private = NULL;
1302
1303 CRM_CHECK(stonith != NULL, return -EINVAL);
1304 CRM_CHECK(stonith->st_private != NULL, return -EINVAL);
1305 private = stonith->st_private;
1306
1307 if (call_id == 0) { // Add global callback
1308 private->op_callback = callback;
1309
1310 } else if (call_id < 0) { // Call failed immediately, so call callback now
1311 if (!(options & st_opt_report_only_success)) {
1313
1314 crm_trace("Call failed, calling %s: %s", callback_name, pcmk_strerror(call_id));
1316 stonith__legacy2status(call_id), NULL);
1317 invoke_fence_action_callback(stonith, call_id, &result,
1318 user_data, callback);
1319 } else {
1320 crm_warn("Fencer call failed: %s", pcmk_strerror(call_id));
1321 }
1322 return FALSE;
1323 }
1324
1325 blob = calloc(1, sizeof(stonith_callback_client_t));
1326 blob->id = callback_name;
1327 blob->only_success = (options & st_opt_report_only_success) ? TRUE : FALSE;
1328 blob->user_data = user_data;
1329 blob->callback = callback;
1330 blob->allow_timeout_updates = (options & st_opt_timeout_updates) ? TRUE : FALSE;
1331
1332 if (timeout > 0) {
1333 set_callback_timeout(blob, stonith, call_id, timeout);
1334 }
1335
1336 pcmk__intkey_table_insert(private->stonith_op_callback_table, call_id,
1337 blob);
1338 crm_trace("Added callback to %s for call %d", callback_name, call_id);
1339
1340 return TRUE;
1341}
1342
1343static void
1344stonith_dump_pending_op(gpointer key, gpointer value, gpointer user_data)
1345{
1346 int call = GPOINTER_TO_INT(key);
1347 stonith_callback_client_t *blob = value;
1348
1349 crm_debug("Call %d (%s): pending", call, pcmk__s(blob->id, "no ID"));
1350}
1351
1352void
1354{
1355 stonith_private_t *private = stonith->st_private;
1356
1357 if (private->stonith_op_callback_table == NULL) {
1358 return;
1359 }
1360 return g_hash_table_foreach(private->stonith_op_callback_table, stonith_dump_pending_op, NULL);
1361}
1362
1370static xmlNode *
1371get_event_data_xml(xmlNode *msg, const char *ntype)
1372{
1373 char *data_addr = crm_strdup_printf("//%s", ntype);
1374 xmlNode *data = get_xpath_object(data_addr, msg, LOG_DEBUG);
1375
1376 free(data_addr);
1377 return data;
1378}
1379
1380/*
1381 <notify t="st_notify" subt="st_device_register" st_op="st_device_register" st_rc="0" >
1382 <st_calldata >
1383 <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" >
1384 <st_calldata >
1385 <st_device_id id="test-id" origin="create_device_registration_xml" agent="fence_virsh" namespace="stonith-ng" >
1386 <attributes ipaddr="localhost" pcmk-portmal="some-host=pcmk-1 pcmk-3=3,4" login="root" identity_file="/root/.ssh/id_dsa" />
1387 </st_device_id>
1388 </st_calldata>
1389 </stonith_command>
1390 </st_calldata>
1391 </notify>
1392
1393 <notify t="st_notify" subt="st_notify_fence" st_op="st_notify_fence" st_rc="0" >
1394 <st_calldata >
1395 <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" />
1396 </st_calldata>
1397 </notify>
1398*/
1399static stonith_event_t *
1400xml_to_event(xmlNode *msg)
1401{
1402 stonith_event_t *event = calloc(1, sizeof(stonith_event_t));
1403 struct event_private *event_private = NULL;
1404
1405 CRM_ASSERT(event != NULL);
1406
1407 event->opaque = calloc(1, sizeof(struct event_private));
1408 CRM_ASSERT(event->opaque != NULL);
1409 event_private = (struct event_private *) event->opaque;
1410
1411 crm_log_xml_trace(msg, "stonith_notify");
1412
1413 // All notification types have the operation result and notification subtype
1414 stonith__xe_get_result(msg, &event_private->result);
1415 event->operation = crm_element_value_copy(msg, F_STONITH_OPERATION);
1416
1417 // @COMPAT The API originally provided the result as a legacy return code
1418 event->result = pcmk_rc2legacy(stonith__result2rc(&event_private->result));
1419
1420 // Some notification subtypes have additional information
1421
1422 if (pcmk__str_eq(event->operation, T_STONITH_NOTIFY_FENCE,
1423 pcmk__str_none)) {
1424 xmlNode *data = get_event_data_xml(msg, event->operation);
1425
1426 if (data == NULL) {
1427 crm_err("No data for %s event", event->operation);
1428 crm_log_xml_notice(msg, "BadEvent");
1429 } else {
1433 event->executioner = crm_element_value_copy(data, F_STONITH_DELEGATE);
1435 event->client_origin = crm_element_value_copy(data, F_STONITH_CLIENTNAME);
1437 }
1438
1439 } else if (pcmk__str_any_of(event->operation,
1442 NULL)) {
1443 xmlNode *data = get_event_data_xml(msg, event->operation);
1444
1445 if (data == NULL) {
1446 crm_err("No data for %s event", event->operation);
1447 crm_log_xml_notice(msg, "BadEvent");
1448 } else {
1450 }
1451 }
1452
1453 return event;
1454}
1455
1456static void
1457event_free(stonith_event_t * event)
1458{
1459 struct event_private *event_private = event->opaque;
1460
1461 free(event->id);
1462 free(event->type);
1463 free(event->message);
1464 free(event->operation);
1465 free(event->origin);
1466 free(event->action);
1467 free(event->target);
1468 free(event->executioner);
1469 free(event->device);
1470 free(event->client_origin);
1471 pcmk__reset_result(&event_private->result);
1472 free(event->opaque);
1473 free(event);
1474}
1475
1476static void
1477stonith_send_notification(gpointer data, gpointer user_data)
1478{
1479 struct notify_blob_s *blob = user_data;
1481 stonith_event_t *st_event = NULL;
1482 const char *event = NULL;
1483
1484 if (blob->xml == NULL) {
1485 crm_warn("Skipping callback - NULL message");
1486 return;
1487 }
1488
1489 event = crm_element_value(blob->xml, F_SUBTYPE);
1490
1491 if (entry == NULL) {
1492 crm_warn("Skipping callback - NULL callback client");
1493 return;
1494
1495 } else if (entry->delete) {
1496 crm_trace("Skipping callback - marked for deletion");
1497 return;
1498
1499 } else if (entry->notify == NULL) {
1500 crm_warn("Skipping callback - NULL callback");
1501 return;
1502
1503 } else if (!pcmk__str_eq(entry->event, event, pcmk__str_none)) {
1504 crm_trace("Skipping callback - event mismatch %p/%s vs. %s", entry, entry->event, event);
1505 return;
1506 }
1507
1508 st_event = xml_to_event(blob->xml);
1509
1510 crm_trace("Invoking callback for %p/%s event...", entry, event);
1511 entry->notify(blob->stonith, st_event);
1512 crm_trace("Callback invoked...");
1513
1514 event_free(st_event);
1515}
1516
1531static int
1532stonith_send_command(stonith_t * stonith, const char *op, xmlNode * data, xmlNode ** output_data,
1533 int call_options, int timeout)
1534{
1535 int rc = 0;
1536 int reply_id = -1;
1537
1538 xmlNode *op_msg = NULL;
1539 xmlNode *op_reply = NULL;
1540 stonith_private_t *native = NULL;
1541
1542 CRM_ASSERT(stonith && stonith->st_private && op);
1543 native = stonith->st_private;
1544
1545 if (output_data != NULL) {
1546 *output_data = NULL;
1547 }
1548
1549 if ((stonith->state == stonith_disconnected) || (native->token == NULL)) {
1550 return -ENOTCONN;
1551 }
1552
1553 /* Increment the call ID, which must be positive to avoid conflicting with
1554 * error codes. This shouldn't be a problem unless the client mucked with
1555 * it or the counter wrapped around.
1556 */
1557 stonith->call_id++;
1558 if (stonith->call_id < 1) {
1559 stonith->call_id = 1;
1560 }
1561
1562 op_msg = stonith_create_op(stonith->call_id, native->token, op, data, call_options);
1563 if (op_msg == NULL) {
1564 return -EINVAL;
1565 }
1566
1568 crm_trace("Sending %s message to fencer with timeout %ds", op, timeout);
1569
1570 if (data) {
1571 const char *delay_s = crm_element_value(data, F_STONITH_DELAY);
1572
1573 if (delay_s) {
1574 crm_xml_add(op_msg, F_STONITH_DELAY, delay_s);
1575 }
1576 }
1577
1578 {
1579 enum crm_ipc_flags ipc_flags = crm_ipc_flags_none;
1580
1581 if (call_options & st_opt_sync_call) {
1582 pcmk__set_ipc_flags(ipc_flags, "stonith command",
1584 }
1585 rc = crm_ipc_send(native->ipc, op_msg, ipc_flags,
1586 1000 * (timeout + 60), &op_reply);
1587 }
1588 free_xml(op_msg);
1589
1590 if (rc < 0) {
1591 crm_perror(LOG_ERR, "Couldn't perform %s operation (timeout=%ds): %d", op, timeout, rc);
1592 rc = -ECOMM;
1593 goto done;
1594 }
1595
1596 crm_log_xml_trace(op_reply, "Reply");
1597
1598 if (!(call_options & st_opt_sync_call)) {
1599 crm_trace("Async call %d, returning", stonith->call_id);
1600 free_xml(op_reply);
1601 return stonith->call_id;
1602 }
1603
1604 rc = pcmk_ok;
1605 crm_element_value_int(op_reply, F_STONITH_CALLID, &reply_id);
1606
1607 if (reply_id == stonith->call_id) {
1609
1610 crm_trace("Synchronous reply %d received", reply_id);
1611
1612 stonith__xe_get_result(op_reply, &result);
1615
1616 if ((call_options & st_opt_discard_reply) || output_data == NULL) {
1617 crm_trace("Discarding reply");
1618
1619 } else {
1620 *output_data = op_reply;
1621 op_reply = NULL; /* Prevent subsequent free */
1622 }
1623
1624 } else if (reply_id <= 0) {
1625 crm_err("Received bad reply: No id set");
1626 crm_log_xml_err(op_reply, "Bad reply");
1627 free_xml(op_reply);
1628 rc = -ENOMSG;
1629
1630 } else {
1631 crm_err("Received bad reply: %d (wanted %d)", reply_id, stonith->call_id);
1632 crm_log_xml_err(op_reply, "Old reply");
1633 free_xml(op_reply);
1634 rc = -ENOMSG;
1635 }
1636
1637 done:
1638 if (crm_ipc_connected(native->ipc) == FALSE) {
1639 crm_err("Fencer disconnected");
1640 free(native->token); native->token = NULL;
1641 stonith->state = stonith_disconnected;
1642 }
1643
1644 free_xml(op_reply);
1645 return rc;
1646}
1647
1648/* Not used with mainloop */
1649bool
1651{
1652 gboolean stay_connected = TRUE;
1653 stonith_private_t *private = NULL;
1654
1655 CRM_ASSERT(st != NULL);
1656 private = st->st_private;
1657
1658 while (crm_ipc_ready(private->ipc)) {
1659
1660 if (crm_ipc_read(private->ipc) > 0) {
1661 const char *msg = crm_ipc_buffer(private->ipc);
1662
1663 stonith_dispatch_internal(msg, strlen(msg), st);
1664 }
1665
1666 if (crm_ipc_connected(private->ipc) == FALSE) {
1667 crm_err("Connection closed");
1668 stay_connected = FALSE;
1669 }
1670 }
1671
1672 return stay_connected;
1673}
1674
1675static int
1676stonith_api_free(stonith_t * stonith)
1677{
1678 int rc = pcmk_ok;
1679
1680 crm_trace("Destroying %p", stonith);
1681
1682 if (stonith->state != stonith_disconnected) {
1683 crm_trace("Disconnecting %p first", stonith);
1684 rc = stonith->cmds->disconnect(stonith);
1685 }
1686
1687 if (stonith->state == stonith_disconnected) {
1688 stonith_private_t *private = stonith->st_private;
1689
1690 crm_trace("Removing %d callbacks", g_hash_table_size(private->stonith_op_callback_table));
1691 g_hash_table_destroy(private->stonith_op_callback_table);
1692
1693 crm_trace("Destroying %d notification clients", g_list_length(private->notify_list));
1694 g_list_free_full(private->notify_list, free);
1695
1696 free(stonith->st_private);
1697 free(stonith->cmds);
1698 free(stonith);
1699
1700 } else {
1701 crm_err("Not free'ing active connection: %s (%d)", pcmk_strerror(rc), rc);
1702 }
1703
1704 return rc;
1705}
1706
1707void
1709{
1710 crm_trace("Destroying %p", stonith);
1711 if(stonith) {
1712 stonith->cmds->free(stonith);
1713 }
1714}
1715
1716static int
1717stonith_api_validate(stonith_t *st, int call_options, const char *rsc_id,
1718 const char *namespace_s, const char *agent,
1719 const stonith_key_value_t *params, int timeout_sec,
1720 char **output, char **error_output)
1721{
1722 /* Validation should be done directly via the agent, so we can get it from
1723 * stonith_admin when the cluster is not running, which is important for
1724 * higher-level tools.
1725 */
1726
1727 int rc = pcmk_ok;
1728
1729 /* Use a dummy node name in case the agent requires a target. We assume the
1730 * actual target doesn't matter for validation purposes (if in practice,
1731 * that is incorrect, we will need to allow the caller to pass the target).
1732 */
1733 const char *target = "node1";
1734 const char *host_arg = NULL;
1735
1736 GHashTable *params_table = pcmk__strkey_table(free, free);
1737
1738 // Convert parameter list to a hash table
1739 for (; params; params = params->next) {
1740 if (pcmk__str_eq(params->key, PCMK_STONITH_HOST_ARGUMENT,
1741 pcmk__str_none)) {
1742 host_arg = params->value;
1743 }
1744 if (!pcmk_stonith_param(params->key)) {
1745 g_hash_table_insert(params_table, strdup(params->key),
1746 strdup(params->value));
1747 }
1748 }
1749
1750#if SUPPORT_CIBSECRETS
1751 rc = pcmk__substitute_secrets(rsc_id, params_table);
1752 if (rc != pcmk_rc_ok) {
1753 crm_warn("Could not replace secret parameters for validation of %s: %s",
1754 agent, pcmk_rc_str(rc));
1755 // rc is standard return value, don't return it in this function
1756 }
1757#endif
1758
1759 if (output) {
1760 *output = NULL;
1761 }
1762 if (error_output) {
1763 *error_output = NULL;
1764 }
1765
1766 if (timeout_sec <= 0) {
1767 timeout_sec = CRMD_METADATA_CALL_TIMEOUT; // Questionable
1768 }
1769
1770 switch (stonith_get_namespace(agent, namespace_s)) {
1771 case st_namespace_rhcs:
1772 rc = stonith__rhcs_validate(st, call_options, target, agent,
1773 params_table, host_arg, timeout_sec,
1774 output, error_output);
1775 break;
1776
1777#if HAVE_STONITH_STONITH_H
1778 case st_namespace_lha:
1779 rc = stonith__lha_validate(st, call_options, target, agent,
1780 params_table, timeout_sec, output,
1781 error_output);
1782 break;
1783#endif
1784
1786 errno = ENOENT;
1787 rc = -errno;
1788
1789 if (error_output) {
1790 *error_output = crm_strdup_printf("Agent %s not found", agent);
1791 } else {
1792 crm_err("Agent %s not found", agent);
1793 }
1794
1795 break;
1796
1797 default:
1798 errno = EOPNOTSUPP;
1799 rc = -errno;
1800
1801 if (error_output) {
1802 *error_output = crm_strdup_printf("Agent %s does not support validation",
1803 agent);
1804 } else {
1805 crm_err("Agent %s does not support validation", agent);
1806 }
1807
1808 break;
1809 }
1810
1811 g_hash_table_destroy(params_table);
1812 return rc;
1813}
1814
1815stonith_t *
1817{
1818 stonith_t *new_stonith = NULL;
1819 stonith_private_t *private = NULL;
1820
1821 new_stonith = calloc(1, sizeof(stonith_t));
1822 if (new_stonith == NULL) {
1823 return NULL;
1824 }
1825
1826 private = calloc(1, sizeof(stonith_private_t));
1827 if (private == NULL) {
1828 free(new_stonith);
1829 return NULL;
1830 }
1831 new_stonith->st_private = private;
1832
1833 private->stonith_op_callback_table = pcmk__intkey_table(stonith_destroy_op_callback);
1834 private->notify_list = NULL;
1835 private->notify_refcnt = 0;
1836 private->notify_deletes = FALSE;
1837
1838 new_stonith->call_id = 1;
1839 new_stonith->state = stonith_disconnected;
1840
1841 new_stonith->cmds = calloc(1, sizeof(stonith_api_operations_t));
1842 if (new_stonith->cmds == NULL) {
1843 free(new_stonith->st_private);
1844 free(new_stonith);
1845 return NULL;
1846 }
1847
1848/* *INDENT-OFF* */
1849 new_stonith->cmds->free = stonith_api_free;
1850 new_stonith->cmds->connect = stonith_api_signon;
1851 new_stonith->cmds->disconnect = stonith_api_signoff;
1852
1853 new_stonith->cmds->list = stonith_api_list;
1854 new_stonith->cmds->monitor = stonith_api_monitor;
1855 new_stonith->cmds->status = stonith_api_status;
1856 new_stonith->cmds->fence = stonith_api_fence;
1857 new_stonith->cmds->fence_with_delay = stonith_api_fence_with_delay;
1858 new_stonith->cmds->confirm = stonith_api_confirm;
1859 new_stonith->cmds->history = stonith_api_history;
1860
1861 new_stonith->cmds->list_agents = stonith_api_device_list;
1862 new_stonith->cmds->metadata = stonith_api_device_metadata;
1863
1864 new_stonith->cmds->query = stonith_api_query;
1865 new_stonith->cmds->remove_device = stonith_api_remove_device;
1866 new_stonith->cmds->register_device = stonith_api_register_device;
1867
1868 new_stonith->cmds->remove_level = stonith_api_remove_level;
1869 new_stonith->cmds->remove_level_full = stonith_api_remove_level_full;
1870 new_stonith->cmds->register_level = stonith_api_register_level;
1871 new_stonith->cmds->register_level_full = stonith_api_register_level_full;
1872
1873 new_stonith->cmds->remove_callback = stonith_api_del_callback;
1874 new_stonith->cmds->register_callback = stonith_api_add_callback;
1875 new_stonith->cmds->remove_notification = stonith_api_del_notification;
1876 new_stonith->cmds->register_notification = stonith_api_add_notification;
1877
1878 new_stonith->cmds->validate = stonith_api_validate;
1879/* *INDENT-ON* */
1880
1881 return new_stonith;
1882}
1883
1893int
1894stonith_api_connect_retry(stonith_t *st, const char *name, int max_attempts)
1895{
1896 int rc = -EINVAL; // if max_attempts is not positive
1897
1898 for (int attempt = 1; attempt <= max_attempts; attempt++) {
1899 rc = st->cmds->connect(st, name, NULL);
1900 if (rc == pcmk_ok) {
1901 return pcmk_ok;
1902 } else if (attempt < max_attempts) {
1903 crm_notice("Fencer connection attempt %d of %d failed (retrying in 2s): %s "
1904 CRM_XS " rc=%d",
1905 attempt, max_attempts, pcmk_strerror(rc), rc);
1906 sleep(2);
1907 }
1908 }
1909 crm_notice("Could not connect to fencer: %s " CRM_XS " rc=%d",
1910 pcmk_strerror(rc), rc);
1911 return rc;
1912}
1913
1915stonith_key_value_add(stonith_key_value_t * head, const char *key, const char *value)
1916{
1917 stonith_key_value_t *p, *end;
1918
1919 p = calloc(1, sizeof(stonith_key_value_t));
1920 pcmk__str_update(&p->key, key);
1921 pcmk__str_update(&p->value, value);
1922
1923 end = head;
1924 while (end && end->next) {
1925 end = end->next;
1926 }
1927
1928 if (end) {
1929 end->next = p;
1930 } else {
1931 head = p;
1932 }
1933
1934 return head;
1935}
1936
1937void
1939{
1941
1942 while (head) {
1943 p = head->next;
1944 if (keys) {
1945 free(head->key);
1946 }
1947 if (values) {
1948 free(head->value);
1949 }
1950 free(head);
1951 head = p;
1952 }
1953}
1954
1955#define api_log_open() openlog("stonith-api", LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON)
1956#define api_log(level, fmt, args...) syslog(level, "%s: "fmt, __func__, args)
1957
1958int
1959stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off)
1960{
1961 int rc = pcmk_ok;
1963 const char *action = off? "off" : "reboot";
1964
1965 api_log_open();
1966 if (st == NULL) {
1967 api_log(LOG_ERR, "API initialization failed, could not kick (%s) node %u/%s",
1968 action, nodeid, uname);
1969 return -EPROTO;
1970 }
1971
1972 rc = st->cmds->connect(st, "stonith-api", NULL);
1973 if (rc != pcmk_ok) {
1974 api_log(LOG_ERR, "Connection failed, could not kick (%s) node %u/%s : %s (%d)",
1975 action, nodeid, uname, pcmk_strerror(rc), rc);
1976 } else {
1977 char *name = (uname == NULL)? pcmk__itoa(nodeid) : strdup(uname);
1978 int opts = 0;
1979
1982 if ((uname == NULL) && (nodeid > 0)) {
1984 }
1985 rc = st->cmds->fence(st, opts, name, action, timeout, 0);
1986 free(name);
1987
1988 if (rc != pcmk_ok) {
1989 api_log(LOG_ERR, "Could not kick (%s) node %u/%s : %s (%d)",
1990 action, nodeid, uname, pcmk_strerror(rc), rc);
1991 } else {
1992 api_log(LOG_NOTICE, "Node %u/%s kicked: %s", nodeid, uname, action);
1993 }
1994 }
1995
1997 return rc;
1998}
1999
2000time_t
2001stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress)
2002{
2003 int rc = pcmk_ok;
2004 time_t when = 0;
2006 stonith_history_t *history = NULL, *hp = NULL;
2007
2008 if (st == NULL) {
2009 api_log(LOG_ERR, "Could not retrieve fence history for %u/%s: "
2010 "API initialization failed", nodeid, uname);
2011 return when;
2012 }
2013
2014 rc = st->cmds->connect(st, "stonith-api", NULL);
2015 if (rc != pcmk_ok) {
2016 api_log(LOG_NOTICE, "Connection failed: %s (%d)", pcmk_strerror(rc), rc);
2017 } else {
2018 int entries = 0;
2019 int progress = 0;
2020 int completed = 0;
2021 int opts = 0;
2022 char *name = (uname == NULL)? pcmk__itoa(nodeid) : strdup(uname);
2023
2025 if ((uname == NULL) && (nodeid > 0)) {
2027 }
2028 rc = st->cmds->history(st, opts, name, &history, 120);
2029 free(name);
2030
2031 for (hp = history; hp; hp = hp->next) {
2032 entries++;
2033 if (in_progress) {
2034 progress++;
2035 if (hp->state != st_done && hp->state != st_failed) {
2036 when = time(NULL);
2037 }
2038
2039 } else if (hp->state == st_done) {
2040 completed++;
2041 if (hp->completed > when) {
2042 when = hp->completed;
2043 }
2044 }
2045 }
2046
2047 stonith_history_free(history);
2048
2049 if(rc == pcmk_ok) {
2050 api_log(LOG_INFO, "Found %d entries for %u/%s: %d in progress, %d completed", entries, nodeid, uname, progress, completed);
2051 } else {
2052 api_log(LOG_ERR, "Could not retrieve fence history for %u/%s: %s (%d)", nodeid, uname, pcmk_strerror(rc), rc);
2053 }
2054 }
2055
2057
2058 if(when) {
2059 api_log(LOG_INFO, "Node %u/%s last kicked at: %ld", nodeid, uname, (long int)when);
2060 }
2061 return when;
2062}
2063
2064bool
2065stonith_agent_exists(const char *agent, int timeout)
2066{
2067 stonith_t *st = NULL;
2068 stonith_key_value_t *devices = NULL;
2069 stonith_key_value_t *dIter = NULL;
2070 bool rc = FALSE;
2071
2072 if (agent == NULL) {
2073 return rc;
2074 }
2075
2076 st = stonith_api_new();
2077 if (st == NULL) {
2078 crm_err("Could not list fence agents: API memory allocation failed");
2079 return FALSE;
2080 }
2081 st->cmds->list_agents(st, st_opt_sync_call, NULL, &devices, timeout == 0 ? 120 : timeout);
2082
2083 for (dIter = devices; dIter != NULL; dIter = dIter->next) {
2084 if (pcmk__str_eq(dIter->value, agent, pcmk__str_none)) {
2085 rc = TRUE;
2086 break;
2087 }
2088 }
2089
2090 stonith_key_value_freeall(devices, 1, 1);
2092 return rc;
2093}
2094
2095const char *
2097{
2098 if (action == NULL) {
2099 return "fencing";
2100 } else if (!strcmp(action, "on")) {
2101 return "unfencing";
2102 } else if (!strcmp(action, "off")) {
2103 return "turning off";
2104 } else {
2105 return action;
2106 }
2107}
2108
2117static void
2118parse_list_line(const char *line, int len, GList **output)
2119{
2120 size_t i = 0;
2121 size_t entry_start = 0;
2122
2123 /* Skip complaints about additional parameters device doesn't understand
2124 *
2125 * @TODO Document or eliminate the implied restriction of target names
2126 */
2127 if (strstr(line, "invalid") || strstr(line, "variable")) {
2128 crm_debug("Skipping list output line: %s", line);
2129 return;
2130 }
2131
2132 // Process line content, character by character
2133 for (i = 0; i <= len; i++) {
2134
2135 if (isspace(line[i]) || (line[i] == ',') || (line[i] == ';')
2136 || (line[i] == '\0')) {
2137 // We've found a separator (i.e. the end of an entry)
2138
2139 int rc = 0;
2140 char *entry = NULL;
2141
2142 if (i == entry_start) {
2143 // Skip leading and sequential separators
2144 entry_start = i + 1;
2145 continue;
2146 }
2147
2148 entry = calloc(i - entry_start + 1, sizeof(char));
2149 CRM_ASSERT(entry != NULL);
2150
2151 /* Read entry, stopping at first separator
2152 *
2153 * @TODO Document or eliminate these character restrictions
2154 */
2155 rc = sscanf(line + entry_start, "%[a-zA-Z0-9_-.]", entry);
2156 if (rc != 1) {
2157 crm_warn("Could not parse list output entry: %s "
2158 CRM_XS " entry_start=%d position=%d",
2159 line + entry_start, entry_start, i);
2160 free(entry);
2161
2162 } else if (pcmk__strcase_any_of(entry, "on", "off", NULL)) {
2163 /* Some agents print the target status in the list output,
2164 * though none are known now (the separate list-status command
2165 * is used for this, but it can also print "UNKNOWN"). To handle
2166 * this possibility, skip such entries.
2167 *
2168 * @TODO Document or eliminate the implied restriction of target
2169 * names.
2170 */
2171 free(entry);
2172
2173 } else {
2174 // We have a valid entry
2175 *output = g_list_append(*output, entry);
2176 }
2177 entry_start = i + 1;
2178 }
2179 }
2180}
2181
2203GList *
2204stonith__parse_targets(const char *target_spec)
2205{
2206 GList *targets = NULL;
2207
2208 if (target_spec != NULL) {
2209 size_t out_len = strlen(target_spec);
2210 size_t line_start = 0; // Starting index of line being processed
2211
2212 for (size_t i = 0; i <= out_len; ++i) {
2213 if ((target_spec[i] == '\n') || (target_spec[i] == '\0')
2214 || ((target_spec[i] == '\\') && (target_spec[i + 1] == 'n'))) {
2215 // We've reached the end of one line of output
2216
2217 int len = i - line_start;
2218
2219 if (len > 0) {
2220 char *line = strndup(target_spec + line_start, len);
2221
2222 line[len] = '\0'; // Because it might be a newline
2223 parse_list_line(line, len, &targets);
2224 free(line);
2225 }
2226 if (target_spec[i] == '\\') {
2227 ++i; // backslash-n takes up two positions
2228 }
2229 line_start = i + 1;
2230 }
2231 }
2232 }
2233 return targets;
2234}
2235
2247const char *
2249{
2250 const char *other = NULL;
2251
2252 for (stonith_history_t *prev_hp = top_history; prev_hp; prev_hp = prev_hp->next) {
2253 if (prev_hp == event) {
2254 break;
2255 }
2256 if ((prev_hp->state == st_done) &&
2257 pcmk__str_eq(event->target, prev_hp->target, pcmk__str_casei) &&
2258 pcmk__str_eq(event->action, prev_hp->action, pcmk__str_none) &&
2259 ((event->completed < prev_hp->completed) ||
2260 ((event->completed == prev_hp->completed) && (event->completed_nsec < prev_hp->completed_nsec)))) {
2261
2262 if ((event->delegate == NULL)
2263 || pcmk__str_eq(event->delegate, prev_hp->delegate,
2264 pcmk__str_casei)) {
2265 // Prefer equivalent fencing by same executioner
2266 return prev_hp->delegate;
2267
2268 } else if (other == NULL) {
2269 // Otherwise remember first successful executioner
2270 other = (prev_hp->delegate == NULL)? "some node" : prev_hp->delegate;
2271 }
2272 }
2273 }
2274 return other;
2275}
2276
2288{
2289 stonith_history_t *new = NULL, *pending = NULL, *hp, *np, *tmp;
2290
2291 for (hp = history; hp; ) {
2292 tmp = hp->next;
2293 if ((hp->state == st_done) || (hp->state == st_failed)) {
2294 /* sort into new */
2295 if ((!new) || (hp->completed > new->completed) ||
2296 ((hp->completed == new->completed) && (hp->completed_nsec > new->completed_nsec))) {
2297 hp->next = new;
2298 new = hp;
2299 } else {
2300 np = new;
2301 do {
2302 if ((!np->next) || (hp->completed > np->next->completed) ||
2303 ((hp->completed == np->next->completed) && (hp->completed_nsec > np->next->completed_nsec))) {
2304 hp->next = np->next;
2305 np->next = hp;
2306 break;
2307 }
2308 np = np->next;
2309 } while (1);
2310 }
2311 } else {
2312 /* put into pending */
2313 hp->next = pending;
2314 pending = hp;
2315 }
2316 hp = tmp;
2317 }
2318
2319 /* pending actions don't have a completed-stamp so make them go front */
2320 if (pending) {
2321 stonith_history_t *last_pending = pending;
2322
2323 while (last_pending->next) {
2324 last_pending = last_pending->next;
2325 }
2326
2327 last_pending->next = new;
2328 new = pending;
2329 }
2330 return new;
2331}
2332
2340const char *
2342{
2343 switch (state) {
2344 case st_query: return "querying";
2345 case st_exec: return "executing";
2346 case st_done: return "completed";
2347 case st_duplicate: return "duplicate";
2348 case st_failed: return "failed";
2349 }
2350 return "unknown";
2351}
2352
2355 bool (*matching_fn)(stonith_history_t *, void *),
2356 void *user_data)
2357{
2358 for (stonith_history_t *hp = history; hp; hp = hp->next) {
2359 if (matching_fn(hp, user_data)) {
2360 return hp;
2361 }
2362 }
2363
2364 return NULL;
2365}
2366
2367bool
2369{
2370 return history->state != st_failed && history->state != st_done;
2371}
2372
2373bool
2375{
2376 return history->state == GPOINTER_TO_INT(user_data);
2377}
2378
2379bool
2381{
2382 return history->state != GPOINTER_TO_INT(user_data);
2383}
2384
2385void
2386stonith__device_parameter_flags(uint32_t *device_flags, const char *device_name,
2387 xmlNode *metadata)
2388{
2389 xmlXPathObjectPtr xpath = NULL;
2390 int max = 0;
2391 int lpc = 0;
2392
2393 CRM_CHECK((device_flags != NULL) && (metadata != NULL), return);
2394
2395 xpath = xpath_search(metadata, "//parameter");
2396 max = numXpathResults(xpath);
2397
2398 if (max <= 0) {
2399 freeXpathObject(xpath);
2400 return;
2401 }
2402
2403 for (lpc = 0; lpc < max; lpc++) {
2404 const char *parameter = NULL;
2405 xmlNode *match = getXpathResult(xpath, lpc);
2406
2407 CRM_LOG_ASSERT(match != NULL);
2408 if (match == NULL) {
2409 continue;
2410 }
2411
2412 parameter = crm_element_value(match, "name");
2413
2414 if (pcmk__str_eq(parameter, "plug", pcmk__str_casei)) {
2415 stonith__set_device_flags(*device_flags, device_name,
2417
2418 } else if (pcmk__str_eq(parameter, "port", pcmk__str_casei)) {
2419 stonith__set_device_flags(*device_flags, device_name,
2421 }
2422 }
2423
2424 freeXpathObject(xpath);
2425}
2426
2445int
2446stonith__metadata_async(const char *agent, int timeout_sec,
2447 void (*callback)(int pid,
2449 void *user_data),
2450 void *user_data)
2451{
2452 switch (stonith_get_namespace(agent, NULL)) {
2453 case st_namespace_rhcs:
2454 {
2455 stonith_action_t *action = NULL;
2456 int rc = pcmk_ok;
2457
2458 action = stonith__action_create(agent, "metadata", NULL, 0,
2459 timeout_sec, NULL, NULL, NULL);
2460
2461 rc = stonith__execute_async(action, user_data, callback, NULL);
2462 if (rc != pcmk_ok) {
2463 callback(0, stonith__action_result(action), user_data);
2465 }
2466 return pcmk_legacy2rc(rc);
2467 }
2468
2469#if HAVE_STONITH_STONITH_H
2470 case st_namespace_lha:
2471 // LHA metadata is simply synthesized, so simulate async
2472 {
2475 .execution_status = PCMK_EXEC_DONE,
2476 .exit_reason = NULL,
2477 .action_stdout = NULL,
2478 .action_stderr = NULL,
2479 };
2480
2481 stonith__lha_metadata(agent, timeout_sec,
2483 callback(0, &result, user_data);
2485 return pcmk_rc_ok;
2486 }
2487#endif
2488
2489 default:
2490 {
2493 .execution_status = PCMK_EXEC_ERROR_HARD,
2494 .exit_reason = crm_strdup_printf("No such agent '%s'",
2495 agent),
2496 .action_stdout = NULL,
2497 .action_stderr = NULL,
2498 };
2499
2500 callback(0, &result, user_data);
2502 return ENOENT;
2503 }
2504 }
2505}
2506
2515int
2517{
2518 if ((data == NULL) || (data->opaque == NULL)) {
2519 return CRM_EX_ERROR;
2520 }
2521 return ((pcmk__action_result_t *) data->opaque)->exit_status;
2522}
2523
2532int
2534{
2535 if ((data == NULL) || (data->opaque == NULL)) {
2536 return PCMK_EXEC_UNKNOWN;
2537 }
2538 return ((pcmk__action_result_t *) data->opaque)->execution_status;
2539}
2540
2549const char *
2551{
2552 if ((data == NULL) || (data->opaque == NULL)) {
2553 return NULL;
2554 }
2555 return ((pcmk__action_result_t *) data->opaque)->exit_reason;
2556}
2557
2566int
2568{
2569 if ((event == NULL) || (event->opaque == NULL)) {
2570 return CRM_EX_ERROR;
2571 } else {
2572 struct event_private *event_private = event->opaque;
2573
2574 return event_private->result.exit_status;
2575 }
2576}
2577
2586int
2588{
2589 if ((event == NULL) || (event->opaque == NULL)) {
2590 return PCMK_EXEC_UNKNOWN;
2591 } else {
2592 struct event_private *event_private = event->opaque;
2593
2594 return event_private->result.execution_status;
2595 }
2596}
2597
2606const char *
2608{
2609 if ((event == NULL) || (event->opaque == NULL)) {
2610 return NULL;
2611 } else {
2612 struct event_private *event_private = event->opaque;
2613
2614 return event_private->result.exit_reason;
2615 }
2616}
2617
2628char *
2630{
2631 // Use somewhat readable defaults
2632 const char *origin = pcmk__s(event->client_origin, "a client");
2633 const char *origin_node = pcmk__s(event->origin, "a node");
2634 const char *executioner = pcmk__s(event->executioner, "the cluster");
2635 const char *device = pcmk__s(event->device, "unknown");
2636 const char *action = pcmk__s(event->action, event->operation);
2637 const char *target = pcmk__s(event->target, "no node");
2638 const char *reason = stonith__event_exit_reason(event);
2639 const char *status;
2640
2641 if (action == NULL) {
2642 action = "(unknown)";
2643 }
2644
2646 status = pcmk_exec_status_str(stonith__event_execution_status(event));
2647 } else if (stonith__event_exit_status(event) != CRM_EX_OK) {
2648 status = pcmk_exec_status_str(PCMK_EXEC_ERROR);
2649 } else {
2650 status = crm_exit_str(CRM_EX_OK);
2651 }
2652
2653 if (pcmk__str_eq(event->operation, T_STONITH_NOTIFY_HISTORY,
2654 pcmk__str_none)) {
2655 return crm_strdup_printf("Fencing history may have changed");
2656
2657 } else if (pcmk__str_eq(event->operation, STONITH_OP_DEVICE_ADD,
2658 pcmk__str_none)) {
2659 return crm_strdup_printf("A fencing device (%s) was added", device);
2660
2661 } else if (pcmk__str_eq(event->operation, STONITH_OP_DEVICE_DEL,
2662 pcmk__str_none)) {
2663 return crm_strdup_printf("A fencing device (%s) was removed", device);
2664
2665 } else if (pcmk__str_eq(event->operation, STONITH_OP_LEVEL_ADD,
2666 pcmk__str_none)) {
2667 return crm_strdup_printf("A fencing topology level (%s) was added",
2668 device);
2669
2670 } else if (pcmk__str_eq(event->operation, STONITH_OP_LEVEL_DEL,
2671 pcmk__str_none)) {
2672 return crm_strdup_printf("A fencing topology level (%s) was removed",
2673 device);
2674 }
2675
2676 // event->operation should be T_STONITH_NOTIFY_FENCE at this point
2677
2678 return crm_strdup_printf("Operation %s of %s by %s for %s@%s: %s%s%s%s (ref=%s)",
2679 action, target, executioner, origin, origin_node,
2680 status,
2681 ((reason == NULL)? "" : " ("), pcmk__s(reason, ""),
2682 ((reason == NULL)? "" : ")"),
2683 pcmk__s(event->id, "(none)"));
2684}
2685
2686
2687// Deprecated functions kept only for backward API compatibility
2688// LCOV_EXCL_START
2689
2690const char *get_stonith_provider(const char *agent, const char *provider);
2691
2692const char *
2693get_stonith_provider(const char *agent, const char *provider)
2694{
2695 return stonith_namespace2text(stonith_get_namespace(agent, provider));
2696}
2697
2698// LCOV_EXCL_STOP
2699// End deprecated API
#define PCMK_STONITH_HOST_ARGUMENT
Definition: agents.h:42
bool pcmk_stonith_param(const char *param)
Check whether a given stonith parameter is handled by Pacemaker.
Definition: agents.c:174
const char * name
Definition: cib.c:24
int pcmk__substitute_secrets(const char *rsc_id, GHashTable *params)
Definition: cib_secrets.c:96
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:145
#define CRMD_METADATA_CALL_TIMEOUT
Definition: crm.h:190
#define F_STONITH_DATE_NSEC
Definition: internal.h:148
int stonith__legacy2status(int rc)
Definition: st_actions.c:404
#define F_STONITH_HISTORY_LIST
Definition: internal.h:146
#define F_STONITH_ORIGIN
Definition: internal.h:145
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:671
#define T_STONITH_TIMEOUT_VALUE
Definition: internal.h:162
@ 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:169
#define STONITH_OP_FENCE
Definition: internal.h:170
#define F_STONITH_DELAY
Definition: internal.h:118
#define F_STONITH_CLIENTID
Definition: internal.h:105
void stonith__destroy_action(stonith_action_t *action)
Definition: st_actions.c:217
#define F_STONITH_REMOTE_OP_ID
Definition: internal.h:111
#define STONITH_OP_DEVICE_ADD
Definition: internal.h:172
#define F_STONITH_DEVICE
Definition: internal.h:153
#define F_STONITH_DATE
Definition: internal.h:147
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:265
#define F_STONITH_TOLERANCE
Definition: internal.h:117
#define STONITH_OP_EXEC
Definition: internal.h:167
#define F_STONITH_TARGET
Definition: internal.h:110
#define stonith__set_device_flags(device_flags, device_id, flags_to_set)
Definition: internal.h:29
#define F_STONITH_NOTIFY_ACTIVATE
Definition: internal.h:137
#define F_STONITH_NOTIFY_DEACTIVATE
Definition: internal.h:138
#define F_STONITH_STATE
Definition: internal.h:149
#define F_STONITH_CALLDATA
Definition: internal.h:108
#define T_STONITH_NG
Definition: internal.h:157
#define STONITH_WATCHDOG_ID
Definition: internal.h:181
#define F_STONITH_CLIENTNAME
Definition: internal.h:135
#define F_STONITH_DELEGATE
Definition: internal.h:139
#define F_STONITH_ACTION
Definition: internal.h:154
void stonith__xe_get_result(xmlNode *xml, pcmk__action_result_t *result)
Definition: st_actions.c:494
#define STONITH_OP_LEVEL_ADD
Definition: internal.h:175
#define T_STONITH_NOTIFY
Definition: internal.h:163
#define STONITH_OP_FENCE_HISTORY
Definition: internal.h:174
pcmk__action_result_t * stonith__action_result(stonith_action_t *action)
Definition: st_actions.c:242
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
#define F_STONITH_OUTPUT
Definition: internal.h:114
#define STONITH_OP_LEVEL_DEL
Definition: internal.h:176
int stonith__result2rc(const pcmk__action_result_t *result)
Definition: st_actions.c:330
#define F_STONITH_OPERATION
Definition: internal.h:109
#define F_STONITH_CALLBACK_TOKEN
Definition: internal.h:134
#define F_STONITH_CALLOPTS
Definition: internal.h:106
#define STONITH_OP_DEVICE_DEL
Definition: internal.h:173
#define F_STONITH_CALLID
Definition: internal.h:107
#define F_STONITH_TIMEOUT
Definition: internal.h:116
G_GNUC_INTERNAL bool stonith__agent_is_rhcs(const char *agent)
Definition: st_rhcs.c:243
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:254
G_GNUC_INTERNAL int stonith__list_rhcs_agents(stonith_key_value_t **devices)
Definition: st_rhcs.c:35
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:217
void crm_ipc_destroy(crm_ipc_t *client)
Definition: ipc_client.c:930
int crm_ipc_send(crm_ipc_t *client, xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Send an IPC XML message.
Definition: ipc_client.c:1209
long crm_ipc_read(crm_ipc_t *client)
Definition: ipc_client.c:1066
int crm_ipc_get_fd(crm_ipc_t *client)
Definition: ipc_client.c:956
crm_ipc_flags
Definition: ipc.h:145
@ crm_ipc_flags_none
Definition: ipc.h:146
@ crm_ipc_client_response
Definition: ipc.h:151
int crm_ipc_ready(crm_ipc_t *client)
Check whether an IPC connection is ready to be read.
Definition: ipc_client.c:1002
bool crm_ipc_connected(crm_ipc_t *client)
Definition: ipc_client.c:970
bool crm_ipc_connect(crm_ipc_t *client)
Establish an IPC connection to a Pacemaker component.
Definition: ipc_client.c:847
void crm_ipc_close(crm_ipc_t *client)
Definition: ipc_client.c:917
const char * crm_ipc_buffer(crm_ipc_t *client)
Definition: ipc_client.c:1115
struct crm_ipc_s crm_ipc_t
Definition: ipc.h:165
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:800
#define pcmk__set_ipc_flags(ipc_flags, ipc_name, flags_to_set)
Definition: ipc_internal.h:205
#define crm_info(fmt, args...)
Definition: logging.h:362
#define crm_warn(fmt, args...)
Definition: logging.h:360
#define CRM_XS
Definition: logging.h:55
#define crm_log_xml_debug(xml, text)
Definition: logging.h:372
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:211
#define crm_log_xml_err(xml, text)
Definition: logging.h:368
#define crm_notice(fmt, args...)
Definition: logging.h:361
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:310
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:227
#define crm_debug(fmt, args...)
Definition: logging.h:364
#define crm_err(fmt, args...)
Definition: logging.h:359
#define LOG_NEVER
Definition: logging.h:47
#define crm_log_xml_trace(xml, text)
Definition: logging.h:373
#define crm_log_xml_warn(xml, text)
Definition: logging.h:369
#define crm_trace(fmt, args...)
Definition: logging.h:365
#define crm_log_xml_notice(xml, text)
Definition: logging.h:370
Wrappers for and extensions to glib mainloop.
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:947
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:916
struct mainloop_io_s mainloop_io_t
Definition: mainloop.h:33
#define G_PRIORITY_MEDIUM
Definition: mainloop.h:182
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:941
#define F_SUBTYPE
Definition: msg_xml.h:65
#define XML_ATTR_STONITH_TARGET_ATTRIBUTE
Definition: msg_xml.h:453
#define XML_TAG_FENCING_LEVEL
Definition: msg_xml.h:448
#define F_XML_TAGNAME
Definition: msg_xml.h:77
#define XML_ATTR_ID
Definition: msg_xml.h:134
#define XML_LRM_ATTR_EXIT_REASON
Definition: msg_xml.h:318
#define XML_ATTR_STONITH_INDEX
Definition: msg_xml.h:449
#define XML_TAG_ATTRS
Definition: msg_xml.h:211
#define F_TYPE
Definition: msg_xml.h:69
#define XML_ATTR_STONITH_DEVICES
Definition: msg_xml.h:454
#define XML_ATTR_STONITH_TARGET_PATTERN
Definition: msg_xml.h:452
#define XML_ATTR_STONITH_TARGET_VALUE
Definition: msg_xml.h:451
#define XML_ATTR_STONITH_TARGET
Definition: msg_xml.h:450
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:517
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:553
void hash2field(gpointer key, gpointer value, gpointer user_data)
Set XML attribute based on hash table entry.
Definition: nvpair.c:770
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:419
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition: nvpair.c:714
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:585
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:323
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
char * strndup(const char *str, size_t len)
#define ECOMM
Definition: portability.h:125
#define ENOTUNIQ
Definition: portability.h:120
const char * pcmk_strerror(int rc)
Definition: results.c:148
#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:476
@ CRM_EX_NOSUCH
Requested item does not exist.
Definition: results.h:270
@ CRM_EX_ERROR
Unspecified error.
Definition: results.h:235
@ CRM_EX_OK
Success.
Definition: results.h:234
@ pcmk_rc_ok
Definition: results.h:148
#define pcmk_ok
Definition: results.h:68
int pcmk_rc2legacy(int rc)
Definition: results.c:521
const char * crm_exit_str(crm_exit_t exit_code)
Definition: results.c:615
@ PCMK_EXEC_DONE
Action completed, result is known.
Definition: results.h:312
@ PCMK_EXEC_ERROR
Execution failed, may be retried.
Definition: results.h:316
@ PCMK_EXEC_TIMEOUT
Action did not complete in time.
Definition: results.h:314
@ PCMK_EXEC_UNKNOWN
Used only to initialize variables.
Definition: results.h:310
@ PCMK_EXEC_ERROR_HARD
Execution failed, do not retry on node.
Definition: results.h:317
int pcmk_legacy2rc(int legacy_rc)
Definition: results.c:534
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:895
#define PCMK__UNKNOWN_RESULT
void pcmk__reset_result(pcmk__action_result_t *result)
Definition: results.c:984
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:2446
void stonith_api_delete(stonith_t *stonith)
Definition: st_client.c:1708
gboolean stonith__watchdog_fencing_enabled_for_node(const char *node)
Definition: st_client.c:231
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:2001
stonith_key_value_t * stonith_key_value_add(stonith_key_value_t *head, const char *key, const char *value)
Definition: st_client.c:1915
const char * stonith__event_exit_reason(stonith_event_t *event)
Definition: st_client.c:2607
int stonith__exit_status(stonith_callback_data_t *data)
Definition: st_client.c:2516
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:2368
GList * stonith__parse_targets(const char *target_spec)
Definition: st_client.c:2204
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:802
void stonith_history_free(stonith_history_t *history)
Definition: st_client.c:755
bool stonith__event_state_neq(stonith_history_t *history, void *user_data)
Definition: st_client.c:2380
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:2386
bool stonith__event_state_eq(stonith_history_t *history, void *user_data)
Definition: st_client.c:2374
const char * stonith_action_str(const char *action)
Turn fence action into a more readable string.
Definition: st_client.c:2096
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:415
CRM_TRACE_INIT_DATA(stonith)
bool stonith_dispatch(stonith_t *st)
Definition: st_client.c:1650
struct stonith_private_s stonith_private_t
const char * stonith__later_succeeded(stonith_history_t *event, stonith_history_t *top_history)
Definition: st_client.c:2248
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:1894
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:2354
#define api_log(level, fmt, args...)
Definition: st_client.c:1956
int stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off)
Definition: st_client.c:1959
const char * get_stonith_provider(const char *agent, const char *provider)
Definition: st_client.c:2693
stonith_history_t * stonith__sort_history(stonith_history_t *history)
Definition: st_client.c:2287
gboolean stonith__watchdog_fencing_enabled_for_node_api(stonith_t *st, const char *node)
Definition: st_client.c:172
int stonith__event_execution_status(stonith_event_t *event)
Definition: st_client.c:2587
int stonith__execution_status(stonith_callback_data_t *data)
Definition: st_client.c:2533
const char * stonith__exit_reason(stonith_callback_data_t *data)
Definition: st_client.c:2550
int(* stonith_op_t)(const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **)
Definition: st_client.c:82
stonith_t * stonith_api_new(void)
Definition: st_client.c:1816
#define api_log_open()
Definition: st_client.c:1955
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:1938
struct stonith_callback_client_s stonith_callback_client_t
bool stonith_agent_exists(const char *agent, int timeout)
Definition: st_client.c:2065
void stonith_dump_pending_callbacks(stonith_t *stonith)
Definition: st_client.c:1353
const char * stonith_op_state_str(enum op_state state)
Return string equivalent of an operation state value.
Definition: st_client.c:2341
int stonith__event_exit_status(stonith_event_t *event)
Definition: st_client.c:2567
char * stonith__event_description(stonith_event_t *event)
Definition: st_client.c:2629
int stonith__lha_metadata(const char *agent, int timeout, char **output)
Definition: st_lha.c:170
int stonith__list_lha_agents(stonith_key_value_t **devices)
Definition: st_lha.c:110
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:272
bool stonith__agent_is_lha(const char *agent)
Determine namespace of a fence agent.
Definition: st_lha.c:83
Fencing aka. STONITH.
#define T_STONITH_NOTIFY_HISTORY
Definition: stonith-ng.h:37
#define T_STONITH_NOTIFY_FENCE
Definition: stonith-ng.h:36
@ st_opt_timeout_updates
Definition: stonith-ng.h:61
@ st_opt_cs_nodeid
Definition: stonith-ng.h:57
@ st_opt_discard_reply
Definition: stonith-ng.h:53
@ st_opt_manual_ack
Definition: stonith-ng.h:52
@ st_opt_allow_suicide
Definition: stonith-ng.h:50
@ st_opt_report_only_success
Definition: stonith-ng.h:63
@ st_opt_sync_call
Definition: stonith-ng.h:58
stonith_namespace
Definition: stonith-ng.h:81
@ st_namespace_invalid
Definition: stonith-ng.h:82
@ st_namespace_rhcs
Definition: stonith-ng.h:89
@ st_namespace_internal
Definition: stonith-ng.h:84
@ st_namespace_any
Definition: stonith-ng.h:83
@ st_namespace_lha
Definition: stonith-ng.h:90
@ stonith_disconnected
Definition: stonith-ng.h:44
@ stonith_connected_command
Definition: stonith-ng.h:42
#define T_STONITH_NOTIFY_DISCONNECT
Definition: stonith-ng.h:35
op_state
Definition: stonith-ng.h:72
@ st_duplicate
Definition: stonith-ng.h:76
@ st_query
Definition: stonith-ng.h:73
@ st_failed
Definition: stonith-ng.h:77
@ st_done
Definition: stonith-ng.h:75
@ st_exec
Definition: stonith-ng.h:74
gboolean pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
Definition: strings.c:883
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:611
void pcmk__str_update(char **str, const char *value)
Definition: strings.c:1190
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:928
@ 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:952
void pcmk__add_separated_word(GString **list, size_t init_size, const char *word, const char *separator)
Definition: strings.c:703
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Dispatch function for an IPC connection used as mainloop source.
Definition: mainloop.h:84
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:542
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:238
int(* free)(stonith_t *st)
Destroy a fencer connection.
Definition: stonith-ng.h:157
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:428
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:341
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:397
int(* metadata)(stonith_t *stonith, int call_options, const char *agent, const char *namespace, char **output, int timeout_sec)
Retrieve a fence agent's metadata.
Definition: stonith-ng.h:258
int(* connect)(stonith_t *st, const char *name, int *stonith_fd)
Connect to the local fencer.
Definition: stonith-ng.h:169
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:223
int(* disconnect)(stonith_t *st)
Disconnect from the local stonith daemon.
Definition: stonith-ng.h:178
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:295
int(* remove_callback)(stonith_t *stonith, int call_id, bool all_callbacks)
Unregister callbacks for asynchronous fencing results.
Definition: stonith-ng.h:444
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:467
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:359
int(* list_agents)(stonith_t *stonith, int call_options, const char *namespace, stonith_key_value_t **devices, int timeout)
Retrieve a list of installed fence agents.
Definition: stonith-ng.h:279
int(* confirm)(stonith_t *stonith, int call_options, const char *target)
Manually confirm that a node has been fenced.
Definition: stonith-ng.h:372
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:324
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:494
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:519
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:309
int(* remove_notification)(stonith_t *stonith, const char *event)
Unregister callbacks for fence notifications.
Definition: stonith-ng.h:409
int(* remove_device)(stonith_t *st, int options, const char *name)
Unregister a fence device with the local fencer.
Definition: stonith-ng.h:190
int(* register_device)(stonith_t *st, int options, const char *id, const char *namespace, const char *agent, const stonith_key_value_t *params)
Register a fence device with the local fencer.
Definition: stonith-ng.h:208
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:385
char * operation
Definition: stonith-ng.h:124
char * executioner
Definition: stonith-ng.h:130
char * client_origin
Definition: stonith-ng.h:135
struct stonith_history_s * next
Definition: stonith-ng.h:112
struct stonith_key_value_s * next
Definition: stonith-ng.h:101
int call_id
Definition: stonith-ng.h:552
enum stonith_state state
Definition: stonith-ng.h:550
void * st_private
Definition: stonith-ng.h:554
stonith_api_operations_t * cmds
Definition: stonith-ng.h:556
int call_id
Definition: internal.h:112
guint ref
Definition: internal.h:114
int timeout
Definition: internal.h:113
stonith_t * stonith
Definition: st_client.c:79
xmlXPathObjectPtr xpath_search(xmlNode *xml_top, const char *path)
Definition: xpath.c:139
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition: xpath.c:214
xmlNode * getXpathResult(xmlXPathObjectPtr xpathObj, int index)
Definition: xpath.c:58
void freeXpathObject(xmlXPathObjectPtr xpathObj)
Definition: xpath.c:39
gboolean add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
Definition: messages.c:160
xmlNode * string2xml(const char *input)
Definition: xml.c:930
void free_xml(xmlNode *child)
Definition: xml.c:885
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:749