pacemaker 2.1.1-77db578727
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
st_client.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2021 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#include <unistd.h>
12#include <stdlib.h>
13#include <stdio.h>
14#include <stdbool.h>
15#include <string.h>
16#include <ctype.h>
17#include <libgen.h>
18#include <inttypes.h>
19
20#include <sys/stat.h>
21#include <sys/types.h>
22#include <sys/wait.h>
23
24#include <glib.h>
25
26#include <crm/crm.h>
27#include <crm/stonith-ng.h>
29#include <crm/msg_xml.h>
30#include <crm/common/xml.h>
32
33#include <crm/common/mainloop.h>
34
36
37struct stonith_action_s {
39 char *agent;
40 char *action;
41 char *victim;
42 GHashTable *args;
43 int timeout;
44 int async;
45 void *userdata;
46 void (*done_cb) (GPid pid, gint status, const char *output, gpointer user_data);
47 void (*fork_cb) (GPid pid, gpointer user_data);
48
49 svc_action_t *svc_action;
50
52 time_t initial_start_time;
53 int tries;
54 int remaining_timeout;
55 int max_retries;
56
57 /* device output data */
58 GPid pid;
59 int rc;
60 char *output;
61 char *error;
62};
63
64typedef struct stonith_private_s {
65 char *token;
66 crm_ipc_t *ipc;
67 mainloop_io_t *source;
68 GHashTable *stonith_op_callback_table;
69 GList *notify_list;
70 int notify_refcnt;
71 bool notify_deletes;
72
73 void (*op_callback) (stonith_t * st, stonith_callback_data_t * data);
74
76
77typedef struct stonith_notify_client_s {
78 const char *event;
79 const char *obj_id; /* implement one day */
80 const char *obj_type; /* implement one day */
81 void (*notify) (stonith_t * st, stonith_event_t * e);
82 bool delete;
83
85
86typedef struct stonith_callback_client_s {
87 void (*callback) (stonith_t * st, stonith_callback_data_t * data);
88 const char *id;
89 void *user_data;
90 gboolean only_success;
91 gboolean allow_timeout_updates;
92 struct timer_rec_s *timer;
93
95
96struct notify_blob_s {
97 stonith_t *stonith;
98 xmlNode *xml;
99};
100
101struct timer_rec_s {
102 int call_id;
103 int timeout;
104 guint ref;
106};
107
108typedef int (*stonith_op_t) (const char *, int, const char *, xmlNode *,
109 xmlNode *, xmlNode *, xmlNode **, xmlNode **);
110
112xmlNode *stonith_create_op(int call_id, const char *token, const char *op, xmlNode * data,
113 int call_options);
114static int stonith_send_command(stonith_t *stonith, const char *op,
115 xmlNode *data, xmlNode **output_data,
116 int call_options, int timeout);
117
118static void stonith_connection_destroy(gpointer user_data);
119static void stonith_send_notification(gpointer data, gpointer user_data);
120static int internal_stonith_action_execute(stonith_action_t * action);
121static void log_action(stonith_action_t *action, pid_t pid);
122
131stonith_text2namespace(const char *namespace_s)
132{
133 if ((namespace_s == NULL) || !strcmp(namespace_s, "any")) {
134 return st_namespace_any;
135
136 } else if (!strcmp(namespace_s, "redhat")
137 || !strcmp(namespace_s, "stonith-ng")) {
138 return st_namespace_rhcs;
139
140 } else if (!strcmp(namespace_s, "internal")) {
142
143 } else if (!strcmp(namespace_s, "heartbeat")) {
144 return st_namespace_lha;
145 }
147}
148
156const char *
158{
159 switch (st_namespace) {
160 case st_namespace_any: return "any";
161 case st_namespace_rhcs: return "stonith-ng";
162 case st_namespace_internal: return "internal";
163 case st_namespace_lha: return "heartbeat";
164 default: break;
165 }
166 return "unsupported";
167}
168
178stonith_get_namespace(const char *agent, const char *namespace_s)
179{
180 if (pcmk__str_eq(namespace_s, "internal", pcmk__str_casei)) {
182 }
183
184 if (stonith__agent_is_rhcs(agent)) {
185 return st_namespace_rhcs;
186 }
187
188#if HAVE_STONITH_STONITH_H
189 if (stonith__agent_is_lha(agent)) {
190 return st_namespace_lha;
191 }
192#endif
193
194 crm_err("Unknown fence agent: %s", agent);
196}
197
198static void
200{
201 if (action->output) {
202 /* Logging the whole string confuses syslog when the string is xml */
203 char *prefix = crm_strdup_printf("%s[%d] stdout:", action->agent, pid);
204
205 crm_log_output(LOG_TRACE, prefix, action->output);
206 free(prefix);
207 }
208
209 if (action->error) {
210 /* Logging the whole string confuses syslog when the string is xml */
211 char *prefix = crm_strdup_printf("%s[%d] stderr:", action->agent, pid);
212
213 crm_log_output(LOG_WARNING, prefix, action->error);
214 free(prefix);
215 }
216}
217
218/* when cycling through the list we don't want to delete items
219 so just mark them and when we know nobody is using the list
220 loop over it to remove the marked items
221 */
222static void
223foreach_notify_entry (stonith_private_t *private,
224 GFunc func,
225 gpointer user_data)
226{
227 private->notify_refcnt++;
228 g_list_foreach(private->notify_list, func, user_data);
229 private->notify_refcnt--;
230 if ((private->notify_refcnt == 0) &&
231 private->notify_deletes) {
232 GList *list_item = private->notify_list;
233
234 private->notify_deletes = FALSE;
235 while (list_item != NULL)
236 {
237 stonith_notify_client_t *list_client = list_item->data;
238 GList *next = g_list_next(list_item);
239
240 if (list_client->delete) {
241 free(list_client);
242 private->notify_list =
243 g_list_delete_link(private->notify_list, list_item);
244 }
245 list_item = next;
246 }
247 }
248}
249
250static void
251stonith_connection_destroy(gpointer user_data)
252{
253 stonith_t *stonith = user_data;
254 stonith_private_t *native = NULL;
255 struct notify_blob_s blob;
256
257 crm_trace("Sending destroyed notification");
258 blob.stonith = stonith;
259 blob.xml = create_xml_node(NULL, "notify");
260
261 native = stonith->st_private;
262 native->ipc = NULL;
263 native->source = NULL;
264
265 free(native->token); native->token = NULL;
266 stonith->state = stonith_disconnected;
269
270 foreach_notify_entry(native, stonith_send_notification, &blob);
271 free_xml(blob.xml);
272}
273
274xmlNode *
276 const char *agent, stonith_key_value_t *params,
277 const char *rsc_provides)
278{
279 xmlNode *data = create_xml_node(NULL, F_STONITH_DEVICE);
280 xmlNode *args = create_xml_node(data, XML_TAG_ATTRS);
281
282#if HAVE_STONITH_STONITH_H
283 if (namespace == st_namespace_any) {
284 namespace = stonith_get_namespace(agent, NULL);
285 }
286 if (namespace == st_namespace_lha) {
287 hash2field((gpointer) "plugin", (gpointer) agent, args);
288 agent = "fence_legacy";
289 }
290#endif
291
294 crm_xml_add(data, "agent", agent);
295 if ((namespace != st_namespace_any) && (namespace != st_namespace_invalid)) {
296 crm_xml_add(data, "namespace", stonith_namespace2text(namespace));
297 }
298 if (rsc_provides) {
299 crm_xml_add(data, "rsc_provides", rsc_provides);
300 }
301
302 for (; params; params = params->next) {
303 hash2field((gpointer) params->key, (gpointer) params->value, args);
304 }
305
306 return data;
307}
308
309static int
310stonith_api_register_device(stonith_t * st, int call_options,
311 const char *id, const char *namespace, const char *agent,
312 stonith_key_value_t * params)
313{
314 int rc = 0;
315 xmlNode *data = NULL;
316
318 agent, params, NULL);
319
320 rc = stonith_send_command(st, STONITH_OP_DEVICE_ADD, data, NULL, call_options, 0);
321 free_xml(data);
322
323 return rc;
324}
325
326static int
327stonith_api_remove_device(stonith_t * st, int call_options, const char *name)
328{
329 int rc = 0;
330 xmlNode *data = NULL;
331
335 rc = stonith_send_command(st, STONITH_OP_DEVICE_DEL, data, NULL, call_options, 0);
336 free_xml(data);
337
338 return rc;
339}
340
341static int
342stonith_api_remove_level_full(stonith_t *st, int options,
343 const char *node, const char *pattern,
344 const char *attr, const char *value, int level)
345{
346 int rc = 0;
347 xmlNode *data = NULL;
348
349 CRM_CHECK(node || pattern || (attr && value), return -EINVAL);
350
353
354 if (node) {
356
357 } else if (pattern) {
359
360 } else {
363 }
364
366 rc = stonith_send_command(st, STONITH_OP_LEVEL_DEL, data, NULL, options, 0);
367 free_xml(data);
368
369 return rc;
370}
371
372static int
373stonith_api_remove_level(stonith_t * st, int options, const char *node, int level)
374{
375 return stonith_api_remove_level_full(st, options, node,
376 NULL, NULL, NULL, level);
377}
378
394xmlNode *
395create_level_registration_xml(const char *node, const char *pattern,
396 const char *attr, const char *value,
397 int level, stonith_key_value_t *device_list)
398{
399 size_t len = 0;
400 char *list = NULL;
401 xmlNode *data;
402
403 CRM_CHECK(node || pattern || (attr && value), return NULL);
404
406 CRM_CHECK(data, return NULL);
407
411
412 if (node) {
414
415 } else if (pattern) {
417
418 } else {
421 }
422
423 // cppcheck seems not to understand the abort logic behind pcmk__realloc
424 // cppcheck-suppress memleak
425 for (; device_list; device_list = device_list->next) {
426 pcmk__add_separated_word(&list, &len, device_list->value, ",");
427 }
428
430
431 free(list);
432 return data;
433}
434
435static int
436stonith_api_register_level_full(stonith_t * st, int options, const char *node,
437 const char *pattern,
438 const char *attr, const char *value,
439 int level, stonith_key_value_t *device_list)
440{
441 int rc = 0;
442 xmlNode *data = create_level_registration_xml(node, pattern, attr, value,
443 level, device_list);
444 CRM_CHECK(data != NULL, return -EINVAL);
445
446 rc = stonith_send_command(st, STONITH_OP_LEVEL_ADD, data, NULL, options, 0);
447 free_xml(data);
448
449 return rc;
450}
451
452static int
453stonith_api_register_level(stonith_t * st, int options, const char *node, int level,
454 stonith_key_value_t * device_list)
455{
456 return stonith_api_register_level_full(st, options, node, NULL, NULL, NULL,
457 level, device_list);
458}
459
460static void
461append_config_arg(gpointer key, gpointer value, gpointer user_data)
462{
463 /* The fencer will filter "action" out when it registers the device,
464 * but ignore it here in case any external API users don't.
465 *
466 * Also filter out parameters handled directly by Pacemaker.
467 */
468 if (!pcmk__str_eq(key, STONITH_ATTR_ACTION_OP, pcmk__str_casei)
469 && !pcmk_stonith_param(key)
470 && (strstr(key, CRM_META) == NULL)
471 && !pcmk__str_eq(key, "crm_feature_set", pcmk__str_casei)) {
472
473 crm_trace("Passing %s=%s with fence action",
474 (const char *) key, (const char *) (value? value : ""));
475 g_hash_table_insert((GHashTable *) user_data,
476 strdup(key), strdup(value? value : ""));
477 }
478}
479
480static GHashTable *
481make_args(const char *agent, const char *action, const char *victim,
482 uint32_t victim_nodeid, GHashTable * device_args,
483 GHashTable * port_map, const char *host_arg)
484{
485 GHashTable *arg_list = NULL;
486 const char *value = NULL;
487
488 CRM_CHECK(action != NULL, return NULL);
489
490 arg_list = pcmk__strkey_table(free, free);
491
492 // Add action to arguments (using an alias if requested)
493 if (device_args) {
494 char buffer[512];
495
496 snprintf(buffer, sizeof(buffer), "pcmk_%s_action", action);
497 value = g_hash_table_lookup(device_args, buffer);
498 if (value) {
499 crm_debug("Substituting '%s' for fence action %s targeting %s",
500 value, action, victim);
501 action = value;
502 }
503 }
504 g_hash_table_insert(arg_list, strdup(STONITH_ATTR_ACTION_OP),
505 strdup(action));
506
507 /* If this is a fencing operation against another node, add more standard
508 * arguments.
509 */
510 if (victim && device_args) {
511 const char *param = NULL;
512
513 /* Always pass the target's name, per
514 * https://github.com/ClusterLabs/fence-agents/blob/master/doc/FenceAgentAPI.md
515 */
516 g_hash_table_insert(arg_list, strdup("nodename"), strdup(victim));
517
518 // If the target's node ID was specified, pass it, too
519 if (victim_nodeid) {
520 char *nodeid = crm_strdup_printf("%" PRIu32, victim_nodeid);
521
522 // cts-fencing looks for this log message
523 crm_info("Passing '%s' as nodeid with fence action '%s' targeting %s",
524 nodeid, action, victim);
525 g_hash_table_insert(arg_list, strdup("nodeid"), nodeid);
526 }
527
528 // Check whether target must be specified in some other way
529 param = g_hash_table_lookup(device_args, PCMK_STONITH_HOST_ARGUMENT);
530 if (!pcmk__str_eq(agent, "fence_legacy", pcmk__str_none)
531 && !pcmk__str_eq(param, "none", pcmk__str_casei)) {
532
533 if (param == NULL) {
534 /* Use the caller's default for pcmk_host_argument, or "port" if
535 * none was given
536 */
537 param = (host_arg == NULL)? "port" : host_arg;
538 }
539 value = g_hash_table_lookup(device_args, param);
540
541 if (pcmk__str_eq(value, "dynamic",
543 /* If the host argument was "dynamic" or not explicitly specified,
544 * add it with the target
545 */
546 const char *alias = NULL;
547
548 if (port_map) {
549 alias = g_hash_table_lookup(port_map, victim);
550 }
551 if (alias == NULL) {
552 alias = victim;
553 }
554 crm_debug("Passing %s='%s' with fence action %s targeting %s",
555 param, alias, action, victim);
556 g_hash_table_insert(arg_list, strdup(param), strdup(alias));
557 }
558 }
559 }
560
561 if (device_args) {
562 g_hash_table_foreach(device_args, append_config_arg, arg_list);
563 }
564
565 return arg_list;
566}
567
574void
576{
577 if (action) {
578 free(action->agent);
579 if (action->args) {
580 g_hash_table_destroy(action->args);
581 }
582 free(action->action);
583 free(action->victim);
584 if (action->svc_action) {
585 services_action_free(action->svc_action);
586 }
587 free(action->output);
588 free(action->error);
589 free(action);
590 }
591}
592
605void
607 char **error_output)
608{
609 if (rc) {
610 *rc = pcmk_ok;
611 }
612 if (output) {
613 *output = NULL;
614 }
615 if (error_output) {
616 *error_output = NULL;
617 }
618 if (action != NULL) {
619 if (rc) {
620 *rc = action->rc;
621 }
622 if (output && action->output) {
623 *output = action->output;
624 action->output = NULL; // hand off memory management to caller
625 }
626 if (error_output && action->error) {
627 *error_output = action->error;
628 action->error = NULL; // hand off memory management to caller
629 }
630 }
631}
632
633#define FAILURE_MAX_RETRIES 2
635stonith_action_create(const char *agent,
636 const char *_action,
637 const char *victim,
638 uint32_t victim_nodeid,
639 int timeout, GHashTable * device_args,
640 GHashTable * port_map, const char *host_arg)
641{
643
644 action = calloc(1, sizeof(stonith_action_t));
645 action->args = make_args(agent, _action, victim, victim_nodeid,
646 device_args, port_map, host_arg);
647 crm_debug("Preparing '%s' action for %s using agent %s",
648 _action, (victim? victim : "no target"), agent);
649 action->agent = strdup(agent);
650 action->action = strdup(_action);
651 if (victim) {
652 action->victim = strdup(victim);
653 }
654 action->timeout = action->remaining_timeout = timeout;
655 action->max_retries = FAILURE_MAX_RETRIES;
656
657 if (device_args) {
658 char buffer[512];
659 const char *value = NULL;
660
661 snprintf(buffer, sizeof(buffer), "pcmk_%s_retries", _action);
662 value = g_hash_table_lookup(device_args, buffer);
663
664 if (value) {
665 action->max_retries = atoi(value);
666 }
667 }
668
669 return action;
670}
671
672static gboolean
673update_remaining_timeout(stonith_action_t * action)
674{
675 int diff = time(NULL) - action->initial_start_time;
676
677 if (action->tries >= action->max_retries) {
678 crm_info("Attempted to execute agent %s (%s) the maximum number of times (%d) allowed",
679 action->agent, action->action, action->max_retries);
680 action->remaining_timeout = 0;
681 } else if ((action->rc != -ETIME) && diff < (action->timeout * 0.7)) {
682 /* only set remaining timeout period if there is 30%
683 * or greater of the original timeout period left */
684 action->remaining_timeout = action->timeout - diff;
685 } else {
686 action->remaining_timeout = 0;
687 }
688 return action->remaining_timeout ? TRUE : FALSE;
689}
690
691static int
692svc_action_to_errno(svc_action_t *svc_action) {
693 int rv = pcmk_ok;
694
695 if (svc_action->rc > 0) {
696 /* Try to provide a useful error code based on the fence agent's
697 * error output.
698 */
699 if (svc_action->rc == PCMK_OCF_TIMEOUT) {
700 rv = -ETIME;
701
702 } else if (svc_action->stderr_data == NULL) {
703 rv = -ENODATA;
704
705 } else if (strstr(svc_action->stderr_data, "imed out")) {
706 /* Some agents have their own internal timeouts */
707 rv = -ETIME;
708
709 } else if (strstr(svc_action->stderr_data, "Unrecognised action")) {
710 rv = -EOPNOTSUPP;
711
712 } else {
713 rv = -pcmk_err_generic;
714 }
715 }
716 return rv;
717}
718
719static void
720stonith_action_async_done(svc_action_t *svc_action)
721{
723
724 action->rc = svc_action_to_errno(svc_action);
725 action->output = svc_action->stdout_data;
726 svc_action->stdout_data = NULL;
727 action->error = svc_action->stderr_data;
728 svc_action->stderr_data = NULL;
729
730 svc_action->params = NULL;
731
732 crm_debug("Child process %d performing action '%s' exited with rc %d",
733 action->pid, action->action, svc_action->rc);
734
735 log_action(action, action->pid);
736
737 if (action->rc != pcmk_ok && update_remaining_timeout(action)) {
738 int rc = internal_stonith_action_execute(action);
739 if (rc == pcmk_ok) {
740 return;
741 }
742 }
743
744 if (action->done_cb) {
745 action->done_cb(action->pid, action->rc, action->output, action->userdata);
746 }
747
748 action->svc_action = NULL; // don't remove our caller
750}
751
752static void
753stonith_action_async_forked(svc_action_t *svc_action)
754{
756
757 action->pid = svc_action->pid;
758 action->svc_action = svc_action;
759
760 if (action->fork_cb) {
761 (action->fork_cb) (svc_action->pid, action->userdata);
762 }
763
764 crm_trace("Child process %d performing action '%s' successfully forked",
765 action->pid, action->action);
766}
767
768static int
769internal_stonith_action_execute(stonith_action_t * action)
770{
771 int rc = -EPROTO;
772 int is_retry = 0;
773 svc_action_t *svc_action = NULL;
774 static int stonith_sequence = 0;
775 char *buffer = NULL;
776
777 if (!action->tries) {
778 action->initial_start_time = time(NULL);
779 }
780 action->tries++;
781
782 if (action->tries > 1) {
783 crm_info("Attempt %d to execute %s (%s). remaining timeout is %d",
784 action->tries, action->agent, action->action, action->remaining_timeout);
785 is_retry = 1;
786 }
787
788 if (action->args == NULL || action->agent == NULL)
789 goto fail;
790
792 basename(action->agent));
793 svc_action = services_action_create_generic(buffer, NULL);
794 free(buffer);
795 svc_action->timeout = 1000 * action->remaining_timeout;
796 svc_action->standard = strdup(PCMK_RESOURCE_CLASS_STONITH);
797 svc_action->id = crm_strdup_printf("%s_%s_%d", basename(action->agent),
798 action->action, action->tries);
799 svc_action->agent = strdup(action->agent);
800 svc_action->sequence = stonith_sequence++;
801 svc_action->params = action->args;
802 svc_action->cb_data = (void *) action;
803 svc_action->flags = pcmk__set_flags_as(__func__, __LINE__,
804 LOG_TRACE, "Action",
805 svc_action->id, svc_action->flags,
807 "SVC_ACTION_NON_BLOCKED");
808
809 /* keep retries from executing out of control and free previous results */
810 if (is_retry) {
811 free(action->output);
812 action->output = NULL;
813 free(action->error);
814 action->error = NULL;
815 sleep(1);
816 }
817
818 if (action->async) {
819 /* async */
821 &stonith_action_async_done,
822 &stonith_action_async_forked) == FALSE) {
823 services_action_free(svc_action);
824 svc_action = NULL;
825 } else {
826 rc = 0;
827 }
828
829 } else {
830 /* sync */
831 if (services_action_sync(svc_action)) {
832 rc = 0;
833 action->rc = svc_action_to_errno(svc_action);
834 action->output = svc_action->stdout_data;
835 svc_action->stdout_data = NULL;
836 action->error = svc_action->stderr_data;
837 svc_action->stderr_data = NULL;
838 } else {
839 action->rc = -ECONNABORTED;
840 rc = action->rc;
841 }
842
843 svc_action->params = NULL;
844 services_action_free(svc_action);
845 }
846
847 fail:
848 return rc;
849}
850
862int
864 void *userdata,
865 void (*done) (GPid pid, int rc, const char *output,
866 gpointer user_data),
867 void (*fork_cb) (GPid pid, gpointer user_data))
868{
869 if (!action) {
870 return -EINVAL;
871 }
872
873 action->userdata = userdata;
874 action->done_cb = done;
875 action->fork_cb = fork_cb;
876 action->async = 1;
877
878 return internal_stonith_action_execute(action);
879}
880
889int
891{
892 int rc = pcmk_ok;
893
894 CRM_CHECK(action != NULL, return -EINVAL);
895
896 // Keep trying until success, max retries, or timeout
897 do {
898 rc = internal_stonith_action_execute(action);
899 } while ((rc != pcmk_ok) && update_remaining_timeout(action));
900
901 return rc;
902}
903
904static int
905stonith_api_device_list(stonith_t * stonith, int call_options, const char *namespace,
906 stonith_key_value_t ** devices, int timeout)
907{
908 int count = 0;
909 enum stonith_namespace ns = stonith_text2namespace(namespace);
910
911 if (devices == NULL) {
912 crm_err("Parameter error: stonith_api_device_list");
913 return -EFAULT;
914 }
915
916#if HAVE_STONITH_STONITH_H
917 // Include Linux-HA agents if requested
918 if ((ns == st_namespace_any) || (ns == st_namespace_lha)) {
919 count += stonith__list_lha_agents(devices);
920 }
921#endif
922
923 // Include Red Hat agents if requested
924 if ((ns == st_namespace_any) || (ns == st_namespace_rhcs)) {
925 count += stonith__list_rhcs_agents(devices);
926 }
927
928 return count;
929}
930
931static int
932stonith_api_device_metadata(stonith_t * stonith, int call_options, const char *agent,
933 const char *namespace, char **output, int timeout)
934{
935 /* By executing meta-data directly, we can get it from stonith_admin when
936 * the cluster is not running, which is important for higher-level tools.
937 */
938
939 enum stonith_namespace ns = stonith_get_namespace(agent, namespace);
940
941 crm_trace("Looking up metadata for %s agent %s",
942 stonith_namespace2text(ns), agent);
943
944 switch (ns) {
946 return stonith__rhcs_metadata(agent, timeout, output);
947
948#if HAVE_STONITH_STONITH_H
949 case st_namespace_lha:
950 return stonith__lha_metadata(agent, timeout, output);
951#endif
952
953 default:
954 crm_err("Can't get fence agent '%s' meta-data: No such agent",
955 agent);
956 break;
957 }
958 return -ENODEV;
959}
960
961static int
962stonith_api_query(stonith_t * stonith, int call_options, const char *target,
963 stonith_key_value_t ** devices, int timeout)
964{
965 int rc = 0, lpc = 0, max = 0;
966
967 xmlNode *data = NULL;
968 xmlNode *output = NULL;
969 xmlXPathObjectPtr xpathObj = NULL;
970
971 CRM_CHECK(devices != NULL, return -EINVAL);
972
977 rc = stonith_send_command(stonith, STONITH_OP_QUERY, data, &output, call_options, timeout);
978
979 if (rc < 0) {
980 return rc;
981 }
982
983 xpathObj = xpath_search(output, "//@agent");
984 if (xpathObj) {
985 max = numXpathResults(xpathObj);
986
987 for (lpc = 0; lpc < max; lpc++) {
988 xmlNode *match = getXpathResult(xpathObj, lpc);
989
990 CRM_LOG_ASSERT(match != NULL);
991 if(match != NULL) {
992 xmlChar *match_path = xmlGetNodePath(match);
993
994 crm_info("%s[%d] = %s", "//@agent", lpc, match_path);
995 free(match_path);
996 *devices = stonith_key_value_add(*devices, NULL, crm_element_value(match, XML_ATTR_ID));
997 }
998 }
999
1000 freeXpathObject(xpathObj);
1001 }
1002
1003 free_xml(output);
1004 free_xml(data);
1005 return max;
1006}
1007
1008static int
1009stonith_api_call(stonith_t * stonith,
1010 int call_options,
1011 const char *id,
1012 const char *action, const char *victim, int timeout, xmlNode ** output)
1013{
1014 int rc = 0;
1015 xmlNode *data = NULL;
1016
1018 crm_xml_add(data, F_STONITH_ORIGIN, __func__);
1022
1023 rc = stonith_send_command(stonith, STONITH_OP_EXEC, data, output, call_options, timeout);
1024 free_xml(data);
1025
1026 return rc;
1027}
1028
1029static int
1030stonith_api_list(stonith_t * stonith, int call_options, const char *id, char **list_info,
1031 int timeout)
1032{
1033 int rc;
1034 xmlNode *output = NULL;
1035
1036 rc = stonith_api_call(stonith, call_options, id, "list", NULL, timeout, &output);
1037
1038 if (output && list_info) {
1039 const char *list_str;
1040
1041 list_str = crm_element_value(output, "st_output");
1042
1043 if (list_str) {
1044 *list_info = strdup(list_str);
1045 }
1046 }
1047
1048 if (output) {
1049 free_xml(output);
1050 }
1051
1052 return rc;
1053}
1054
1055static int
1056stonith_api_monitor(stonith_t * stonith, int call_options, const char *id, int timeout)
1057{
1058 return stonith_api_call(stonith, call_options, id, "monitor", NULL, timeout, NULL);
1059}
1060
1061static int
1062stonith_api_status(stonith_t * stonith, int call_options, const char *id, const char *port,
1063 int timeout)
1064{
1065 return stonith_api_call(stonith, call_options, id, "status", port, timeout, NULL);
1066}
1067
1068static int
1069stonith_api_fence_with_delay(stonith_t * stonith, int call_options, const char *node,
1070 const char *action, int timeout, int tolerance, int delay)
1071{
1072 int rc = 0;
1073 xmlNode *data = NULL;
1074
1075 data = create_xml_node(NULL, __func__);
1081
1082 rc = stonith_send_command(stonith, STONITH_OP_FENCE, data, NULL, call_options, timeout);
1083 free_xml(data);
1084
1085 return rc;
1086}
1087
1088static int
1089stonith_api_fence(stonith_t * stonith, int call_options, const char *node, const char *action,
1090 int timeout, int tolerance)
1091{
1092 return stonith_api_fence_with_delay(stonith, call_options, node, action,
1093 timeout, tolerance, 0);
1094}
1095
1096static int
1097stonith_api_confirm(stonith_t * stonith, int call_options, const char *target)
1098{
1100 return stonith_api_fence(stonith, call_options, target, "off", 0, 0);
1101}
1102
1103static int
1104stonith_api_history(stonith_t * stonith, int call_options, const char *node,
1105 stonith_history_t ** history, int timeout)
1106{
1107 int rc = 0;
1108 xmlNode *data = NULL;
1109 xmlNode *output = NULL;
1110 stonith_history_t *last = NULL;
1111
1112 *history = NULL;
1113
1114 if (node) {
1115 data = create_xml_node(NULL, __func__);
1117 }
1118
1119 stonith__set_call_options(call_options, node, st_opt_sync_call);
1120 rc = stonith_send_command(stonith, STONITH_OP_FENCE_HISTORY, data, &output,
1121 call_options, timeout);
1122 free_xml(data);
1123
1124 if (rc == 0) {
1125 xmlNode *op = NULL;
1126 xmlNode *reply = get_xpath_object("//" F_STONITH_HISTORY_LIST, output,
1127 LOG_NEVER);
1128
1129 for (op = pcmk__xml_first_child(reply); op != NULL;
1130 op = pcmk__xml_next(op)) {
1131 stonith_history_t *kvp;
1132 long long completed;
1133
1134 kvp = calloc(1, sizeof(stonith_history_t));
1140 crm_element_value_ll(op, F_STONITH_DATE, &completed);
1141 kvp->completed = (time_t) completed;
1143
1144 if (last) {
1145 last->next = kvp;
1146 } else {
1147 *history = kvp;
1148 }
1149 last = kvp;
1150 }
1151 }
1152
1153 free_xml(output);
1154
1155 return rc;
1156}
1157
1159{
1160 stonith_history_t *hp, *hp_old;
1161
1162 for (hp = history; hp; hp_old = hp, hp = hp->next, free(hp_old)) {
1163 free(hp->target);
1164 free(hp->action);
1165 free(hp->origin);
1166 free(hp->delegate);
1167 free(hp->client);
1168 }
1169}
1170
1171static gint
1172stonithlib_GCompareFunc(gconstpointer a, gconstpointer b)
1173{
1174 int rc = 0;
1175 const stonith_notify_client_t *a_client = a;
1176 const stonith_notify_client_t *b_client = b;
1177
1178 if (a_client->delete || b_client->delete) {
1179 /* make entries marked for deletion not findable */
1180 return -1;
1181 }
1182 CRM_CHECK(a_client->event != NULL && b_client->event != NULL, return 0);
1183 rc = strcmp(a_client->event, b_client->event);
1184 if (rc == 0) {
1185 if (a_client->notify == NULL || b_client->notify == NULL) {
1186 return 0;
1187
1188 } else if (a_client->notify == b_client->notify) {
1189 return 0;
1190
1191 } else if (((long)a_client->notify) < ((long)b_client->notify)) {
1192 crm_err("callbacks for %s are not equal: %p vs. %p",
1193 a_client->event, a_client->notify, b_client->notify);
1194 return -1;
1195 }
1196 crm_err("callbacks for %s are not equal: %p vs. %p",
1197 a_client->event, a_client->notify, b_client->notify);
1198 return 1;
1199 }
1200 return rc;
1201}
1202
1203xmlNode *
1204stonith_create_op(int call_id, const char *token, const char *op, xmlNode * data, int call_options)
1205{
1206 xmlNode *op_msg = create_xml_node(NULL, "stonith_command");
1207
1208 CRM_CHECK(op_msg != NULL, return NULL);
1209 CRM_CHECK(token != NULL, return NULL);
1210
1211 crm_xml_add(op_msg, F_XML_TAGNAME, "stonith_command");
1212
1214 crm_xml_add(op_msg, F_STONITH_CALLBACK_TOKEN, token);
1215 crm_xml_add(op_msg, F_STONITH_OPERATION, op);
1216 crm_xml_add_int(op_msg, F_STONITH_CALLID, call_id);
1217 crm_trace("Sending call options: %.8lx, %d", (long)call_options, call_options);
1218 crm_xml_add_int(op_msg, F_STONITH_CALLOPTS, call_options);
1219
1220 if (data != NULL) {
1222 }
1223
1224 return op_msg;
1225}
1226
1227static void
1228stonith_destroy_op_callback(gpointer data)
1229{
1231
1232 if (blob->timer && blob->timer->ref > 0) {
1233 g_source_remove(blob->timer->ref);
1234 }
1235 free(blob->timer);
1236 free(blob);
1237}
1238
1239static int
1240stonith_api_signoff(stonith_t * stonith)
1241{
1242 stonith_private_t *native = stonith->st_private;
1243
1244 crm_debug("Disconnecting from the fencer");
1245
1246 if (native->source != NULL) {
1247 /* Attached to mainloop */
1248 mainloop_del_ipc_client(native->source);
1249 native->source = NULL;
1250 native->ipc = NULL;
1251
1252 } else if (native->ipc) {
1253 /* Not attached to mainloop */
1254 crm_ipc_t *ipc = native->ipc;
1255
1256 native->ipc = NULL;
1257 crm_ipc_close(ipc);
1258 crm_ipc_destroy(ipc);
1259 }
1260
1261 free(native->token); native->token = NULL;
1262 stonith->state = stonith_disconnected;
1263 return pcmk_ok;
1264}
1265
1266static int
1267stonith_api_del_callback(stonith_t * stonith, int call_id, bool all_callbacks)
1268{
1269 stonith_private_t *private = stonith->st_private;
1270
1271 if (all_callbacks) {
1272 private->op_callback = NULL;
1273 g_hash_table_destroy(private->stonith_op_callback_table);
1274 private->stonith_op_callback_table = pcmk__intkey_table(stonith_destroy_op_callback);
1275
1276 } else if (call_id == 0) {
1277 private->op_callback = NULL;
1278
1279 } else {
1280 pcmk__intkey_table_remove(private->stonith_op_callback_table, call_id);
1281 }
1282 return pcmk_ok;
1283}
1284
1285static void
1286invoke_callback(stonith_t * st, int call_id, int rc, void *userdata,
1287 void (*callback) (stonith_t * st, stonith_callback_data_t * data))
1288{
1290
1291 data.call_id = call_id;
1292 data.rc = rc;
1293 data.userdata = userdata;
1294
1295 callback(st, &data);
1296}
1297
1298static void
1299stonith_perform_callback(stonith_t * stonith, xmlNode * msg, int call_id, int rc)
1300{
1301 stonith_private_t *private = NULL;
1302 stonith_callback_client_t *blob = NULL;
1303 stonith_callback_client_t local_blob;
1304
1305 CRM_CHECK(stonith != NULL, return);
1306 CRM_CHECK(stonith->st_private != NULL, return);
1307
1308 private = stonith->st_private;
1309
1310 local_blob.id = NULL;
1311 local_blob.callback = NULL;
1312 local_blob.user_data = NULL;
1313 local_blob.only_success = FALSE;
1314
1315 if (msg != NULL) {
1318 }
1319
1320 CRM_CHECK(call_id > 0, crm_log_xml_err(msg, "Bad result"));
1321
1322 blob = pcmk__intkey_table_lookup(private->stonith_op_callback_table,
1323 call_id);
1324 if (blob != NULL) {
1325 local_blob = *blob;
1326 blob = NULL;
1327
1328 stonith_api_del_callback(stonith, call_id, FALSE);
1329
1330 } else {
1331 crm_trace("No callback found for call %d", call_id);
1332 local_blob.callback = NULL;
1333 }
1334
1335 if (local_blob.callback != NULL && (rc == pcmk_ok || local_blob.only_success == FALSE)) {
1336 crm_trace("Invoking callback %s for call %d", crm_str(local_blob.id), call_id);
1337 invoke_callback(stonith, call_id, rc, local_blob.user_data, local_blob.callback);
1338
1339 } else if (private->op_callback == NULL && rc != pcmk_ok) {
1340 crm_warn("Fencing command failed: %s", pcmk_strerror(rc));
1341 crm_log_xml_debug(msg, "Failed fence update");
1342 }
1343
1344 if (private->op_callback != NULL) {
1345 crm_trace("Invoking global callback for call %d", call_id);
1346 invoke_callback(stonith, call_id, rc, NULL, private->op_callback);
1347 }
1348 crm_trace("OP callback activated.");
1349}
1350
1351static gboolean
1352stonith_async_timeout_handler(gpointer data)
1353{
1354 struct timer_rec_s *timer = data;
1355
1356 crm_err("Async call %d timed out after %dms", timer->call_id, timer->timeout);
1357 stonith_perform_callback(timer->stonith, NULL, timer->call_id, -ETIME);
1358
1359 /* Always return TRUE, never remove the handler
1360 * We do that in stonith_del_callback()
1361 */
1362 return TRUE;
1363}
1364
1365static void
1366set_callback_timeout(stonith_callback_client_t * callback, stonith_t * stonith, int call_id,
1367 int timeout)
1368{
1369 struct timer_rec_s *async_timer = callback->timer;
1370
1371 if (timeout <= 0) {
1372 return;
1373 }
1374
1375 if (!async_timer) {
1376 async_timer = calloc(1, sizeof(struct timer_rec_s));
1377 callback->timer = async_timer;
1378 }
1379
1380 async_timer->stonith = stonith;
1381 async_timer->call_id = call_id;
1382 /* Allow a fair bit of grace to allow the server to tell us of a timeout
1383 * This is only a fallback
1384 */
1385 async_timer->timeout = (timeout + 60) * 1000;
1386 if (async_timer->ref) {
1387 g_source_remove(async_timer->ref);
1388 }
1389 async_timer->ref =
1390 g_timeout_add(async_timer->timeout, stonith_async_timeout_handler, async_timer);
1391}
1392
1393static void
1394update_callback_timeout(int call_id, int timeout, stonith_t * st)
1395{
1396 stonith_callback_client_t *callback = NULL;
1397 stonith_private_t *private = st->st_private;
1398
1399 callback = pcmk__intkey_table_lookup(private->stonith_op_callback_table,
1400 call_id);
1401 if (!callback || !callback->allow_timeout_updates) {
1402 return;
1403 }
1404
1405 set_callback_timeout(callback, st, call_id, timeout);
1406}
1407
1408static int
1409stonith_dispatch_internal(const char *buffer, ssize_t length, gpointer userdata)
1410{
1411 const char *type = NULL;
1412 struct notify_blob_s blob;
1413
1414 stonith_t *st = userdata;
1415 stonith_private_t *private = NULL;
1416
1417 CRM_ASSERT(st != NULL);
1418 private = st->st_private;
1419
1420 blob.stonith = st;
1421 blob.xml = string2xml(buffer);
1422 if (blob.xml == NULL) {
1423 crm_warn("Received malformed message from fencer: %s", buffer);
1424 return 0;
1425 }
1426
1427 /* do callbacks */
1428 type = crm_element_value(blob.xml, F_TYPE);
1429 crm_trace("Activating %s callbacks...", type);
1430
1431 if (pcmk__str_eq(type, T_STONITH_NG, pcmk__str_casei)) {
1432 stonith_perform_callback(st, blob.xml, 0, 0);
1433
1434 } else if (pcmk__str_eq(type, T_STONITH_NOTIFY, pcmk__str_casei)) {
1435 foreach_notify_entry(private, stonith_send_notification, &blob);
1436 } else if (pcmk__str_eq(type, T_STONITH_TIMEOUT_VALUE, pcmk__str_casei)) {
1437 int call_id = 0;
1438 int timeout = 0;
1439
1441 crm_element_value_int(blob.xml, F_STONITH_CALLID, &call_id);
1442
1443 update_callback_timeout(call_id, timeout, st);
1444 } else {
1445 crm_err("Unknown message type: %s", type);
1446 crm_log_xml_warn(blob.xml, "BadReply");
1447 }
1448
1449 free_xml(blob.xml);
1450 return 1;
1451}
1452
1453static int
1454stonith_api_signon(stonith_t * stonith, const char *name, int *stonith_fd)
1455{
1456 int rc = pcmk_ok;
1457 stonith_private_t *native = NULL;
1458 const char *display_name = name? name : "client";
1459
1460 struct ipc_client_callbacks st_callbacks = {
1461 .dispatch = stonith_dispatch_internal,
1462 .destroy = stonith_connection_destroy
1463 };
1464
1465 CRM_CHECK(stonith != NULL, return -EINVAL);
1466
1467 native = stonith->st_private;
1468 CRM_ASSERT(native != NULL);
1469
1470 crm_debug("Attempting fencer connection by %s with%s mainloop",
1471 display_name, (stonith_fd? "out" : ""));
1472
1474 if (stonith_fd) {
1475 /* No mainloop */
1476 native->ipc = crm_ipc_new("stonith-ng", 0);
1477
1478 if (native->ipc && crm_ipc_connect(native->ipc)) {
1479 *stonith_fd = crm_ipc_get_fd(native->ipc);
1480 } else if (native->ipc) {
1481 crm_ipc_close(native->ipc);
1482 crm_ipc_destroy(native->ipc);
1483 native->ipc = NULL;
1484 }
1485
1486 } else {
1487 /* With mainloop */
1488 native->source =
1489 mainloop_add_ipc_client("stonith-ng", G_PRIORITY_MEDIUM, 0, stonith, &st_callbacks);
1490 native->ipc = mainloop_get_ipc_client(native->source);
1491 }
1492
1493 if (native->ipc == NULL) {
1494 rc = -ENOTCONN;
1495 } else {
1496 xmlNode *reply = NULL;
1497 xmlNode *hello = create_xml_node(NULL, "stonith_command");
1498
1502 rc = crm_ipc_send(native->ipc, hello, crm_ipc_client_response, -1, &reply);
1503
1504 if (rc < 0) {
1505 crm_debug("Couldn't register with the fencer: %s "
1506 CRM_XS " rc=%d", pcmk_strerror(rc), rc);
1507 rc = -ECOMM;
1508
1509 } else if (reply == NULL) {
1510 crm_debug("Couldn't register with the fencer: no reply");
1511 rc = -EPROTO;
1512
1513 } else {
1514 const char *msg_type = crm_element_value(reply, F_STONITH_OPERATION);
1515
1516 native->token = crm_element_value_copy(reply, F_STONITH_CLIENTID);
1517 if (!pcmk__str_eq(msg_type, CRM_OP_REGISTER, pcmk__str_casei)) {
1518 crm_debug("Couldn't register with the fencer: invalid reply type '%s'",
1519 (msg_type? msg_type : "(missing)"));
1520 crm_log_xml_debug(reply, "Invalid fencer reply");
1521 rc = -EPROTO;
1522
1523 } else if (native->token == NULL) {
1524 crm_debug("Couldn't register with the fencer: no token in reply");
1525 crm_log_xml_debug(reply, "Invalid fencer reply");
1526 rc = -EPROTO;
1527
1528 } else {
1529#if HAVE_MSGFROMIPC_TIMEOUT
1531#endif
1532 crm_debug("Connection to fencer by %s succeeded (registration token: %s)",
1533 display_name, native->token);
1534 rc = pcmk_ok;
1535 }
1536 }
1537
1538 free_xml(reply);
1539 free_xml(hello);
1540 }
1541
1542 if (rc != pcmk_ok) {
1543 crm_debug("Connection attempt to fencer by %s failed: %s "
1544 CRM_XS " rc=%d", display_name, pcmk_strerror(rc), rc);
1545 stonith->cmds->disconnect(stonith);
1546 }
1547 return rc;
1548}
1549
1550static int
1551stonith_set_notification(stonith_t * stonith, const char *callback, int enabled)
1552{
1553 int rc = pcmk_ok;
1554 xmlNode *notify_msg = create_xml_node(NULL, __func__);
1555 stonith_private_t *native = stonith->st_private;
1556
1557 if (stonith->state != stonith_disconnected) {
1558
1560 if (enabled) {
1561 crm_xml_add(notify_msg, F_STONITH_NOTIFY_ACTIVATE, callback);
1562 } else {
1563 crm_xml_add(notify_msg, F_STONITH_NOTIFY_DEACTIVATE, callback);
1564 }
1565
1566 rc = crm_ipc_send(native->ipc, notify_msg, crm_ipc_client_response, -1, NULL);
1567 if (rc < 0) {
1568 crm_perror(LOG_DEBUG, "Couldn't register for fencing notifications: %d", rc);
1569 rc = -ECOMM;
1570 } else {
1571 rc = pcmk_ok;
1572 }
1573 }
1574
1575 free_xml(notify_msg);
1576 return rc;
1577}
1578
1579static int
1580stonith_api_add_notification(stonith_t * stonith, const char *event,
1581 void (*callback) (stonith_t * stonith, stonith_event_t * e))
1582{
1583 GList *list_item = NULL;
1584 stonith_notify_client_t *new_client = NULL;
1585 stonith_private_t *private = NULL;
1586
1587 private = stonith->st_private;
1588 crm_trace("Adding callback for %s events (%d)", event, g_list_length(private->notify_list));
1589
1590 new_client = calloc(1, sizeof(stonith_notify_client_t));
1591 new_client->event = event;
1592 new_client->notify = callback;
1593
1594 list_item = g_list_find_custom(private->notify_list, new_client, stonithlib_GCompareFunc);
1595
1596 if (list_item != NULL) {
1597 crm_warn("Callback already present");
1598 free(new_client);
1599 return -ENOTUNIQ;
1600
1601 } else {
1602 private->notify_list = g_list_append(private->notify_list, new_client);
1603
1604 stonith_set_notification(stonith, event, 1);
1605
1606 crm_trace("Callback added (%d)", g_list_length(private->notify_list));
1607 }
1608 return pcmk_ok;
1609}
1610
1611static int
1612stonith_api_del_notification(stonith_t * stonith, const char *event)
1613{
1614 GList *list_item = NULL;
1615 stonith_notify_client_t *new_client = NULL;
1616 stonith_private_t *private = NULL;
1617
1618 crm_debug("Removing callback for %s events", event);
1619
1620 private = stonith->st_private;
1621 new_client = calloc(1, sizeof(stonith_notify_client_t));
1622 new_client->event = event;
1623 new_client->notify = NULL;
1624
1625 list_item = g_list_find_custom(private->notify_list, new_client, stonithlib_GCompareFunc);
1626
1627 stonith_set_notification(stonith, event, 0);
1628
1629 if (list_item != NULL) {
1630 stonith_notify_client_t *list_client = list_item->data;
1631
1632 if (private->notify_refcnt) {
1633 list_client->delete = TRUE;
1634 private->notify_deletes = TRUE;
1635 } else {
1636 private->notify_list = g_list_remove(private->notify_list, list_client);
1637 free(list_client);
1638 }
1639
1640 crm_trace("Removed callback");
1641
1642 } else {
1643 crm_trace("Callback not present");
1644 }
1645 free(new_client);
1646 return pcmk_ok;
1647}
1648
1649static int
1650stonith_api_add_callback(stonith_t * stonith, int call_id, int timeout, int options,
1651 void *user_data, const char *callback_name,
1652 void (*callback) (stonith_t * st, stonith_callback_data_t * data))
1653{
1654 stonith_callback_client_t *blob = NULL;
1655 stonith_private_t *private = NULL;
1656
1657 CRM_CHECK(stonith != NULL, return -EINVAL);
1658 CRM_CHECK(stonith->st_private != NULL, return -EINVAL);
1659 private = stonith->st_private;
1660
1661 if (call_id == 0) {
1662 private->op_callback = callback;
1663
1664 } else if (call_id < 0) {
1665 if (!(options & st_opt_report_only_success)) {
1666 crm_trace("Call failed, calling %s: %s", callback_name, pcmk_strerror(call_id));
1667 invoke_callback(stonith, call_id, call_id, user_data, callback);
1668 } else {
1669 crm_warn("Fencer call failed: %s", pcmk_strerror(call_id));
1670 }
1671 return FALSE;
1672 }
1673
1674 blob = calloc(1, sizeof(stonith_callback_client_t));
1675 blob->id = callback_name;
1676 blob->only_success = (options & st_opt_report_only_success) ? TRUE : FALSE;
1677 blob->user_data = user_data;
1678 blob->callback = callback;
1679 blob->allow_timeout_updates = (options & st_opt_timeout_updates) ? TRUE : FALSE;
1680
1681 if (timeout > 0) {
1682 set_callback_timeout(blob, stonith, call_id, timeout);
1683 }
1684
1685 pcmk__intkey_table_insert(private->stonith_op_callback_table, call_id,
1686 blob);
1687 crm_trace("Added callback to %s for call %d", callback_name, call_id);
1688
1689 return TRUE;
1690}
1691
1692static void
1693stonith_dump_pending_op(gpointer key, gpointer value, gpointer user_data)
1694{
1695 int call = GPOINTER_TO_INT(key);
1696 stonith_callback_client_t *blob = value;
1697
1698 crm_debug("Call %d (%s): pending", call, crm_str(blob->id));
1699}
1700
1701void
1703{
1704 stonith_private_t *private = stonith->st_private;
1705
1706 if (private->stonith_op_callback_table == NULL) {
1707 return;
1708 }
1709 return g_hash_table_foreach(private->stonith_op_callback_table, stonith_dump_pending_op, NULL);
1710}
1711
1712/*
1713 <notify t="st_notify" subt="st_device_register" st_op="st_device_register" st_rc="0" >
1714 <st_calldata >
1715 <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" >
1716 <st_calldata >
1717 <st_device_id id="test-id" origin="create_device_registration_xml" agent="fence_virsh" namespace="stonith-ng" >
1718 <attributes ipaddr="localhost" pcmk-portmal="some-host=pcmk-1 pcmk-3=3,4" login="root" identity_file="/root/.ssh/id_dsa" />
1719 </st_device_id>
1720 </st_calldata>
1721 </stonith_command>
1722 </st_calldata>
1723 </notify>
1724
1725 <notify t="st_notify" subt="st_notify_fence" st_op="st_notify_fence" st_rc="0" >
1726 <st_calldata >
1727 <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" />
1728 </st_calldata>
1729 </notify>
1730*/
1731static stonith_event_t *
1732xml_to_event(xmlNode * msg)
1733{
1734 stonith_event_t *event = calloc(1, sizeof(stonith_event_t));
1735 const char *ntype = crm_element_value(msg, F_SUBTYPE);
1736 char *data_addr = crm_strdup_printf("//%s", ntype);
1737 xmlNode *data = get_xpath_object(data_addr, msg, LOG_DEBUG);
1738
1739 crm_log_xml_trace(msg, "stonith_notify");
1740
1741 crm_element_value_int(msg, F_STONITH_RC, &(event->result));
1742
1743 if (pcmk__str_eq(ntype, T_STONITH_NOTIFY_FENCE, pcmk__str_casei)) {
1744 event->operation = crm_element_value_copy(msg, F_STONITH_OPERATION);
1745
1746 if (data) {
1750 event->executioner = crm_element_value_copy(data, F_STONITH_DELEGATE);
1752 event->client_origin = crm_element_value_copy(data, F_STONITH_CLIENTNAME);
1754
1755 } else {
1756 crm_err("No data for %s event", ntype);
1757 crm_log_xml_notice(msg, "BadEvent");
1758 }
1759 }
1760
1761 free(data_addr);
1762 return event;
1763}
1764
1765static void
1766event_free(stonith_event_t * event)
1767{
1768 free(event->id);
1769 free(event->type);
1770 free(event->message);
1771 free(event->operation);
1772 free(event->origin);
1773 free(event->action);
1774 free(event->target);
1775 free(event->executioner);
1776 free(event->device);
1777 free(event->client_origin);
1778 free(event);
1779}
1780
1781static void
1782stonith_send_notification(gpointer data, gpointer user_data)
1783{
1784 struct notify_blob_s *blob = user_data;
1786 stonith_event_t *st_event = NULL;
1787 const char *event = NULL;
1788
1789 if (blob->xml == NULL) {
1790 crm_warn("Skipping callback - NULL message");
1791 return;
1792 }
1793
1794 event = crm_element_value(blob->xml, F_SUBTYPE);
1795
1796 if (entry == NULL) {
1797 crm_warn("Skipping callback - NULL callback client");
1798 return;
1799
1800 } else if (entry->delete) {
1801 crm_trace("Skipping callback - marked for deletion");
1802 return;
1803
1804 } else if (entry->notify == NULL) {
1805 crm_warn("Skipping callback - NULL callback");
1806 return;
1807
1808 } else if (!pcmk__str_eq(entry->event, event, pcmk__str_casei)) {
1809 crm_trace("Skipping callback - event mismatch %p/%s vs. %s", entry, entry->event, event);
1810 return;
1811 }
1812
1813 st_event = xml_to_event(blob->xml);
1814
1815 crm_trace("Invoking callback for %p/%s event...", entry, event);
1816 entry->notify(blob->stonith, st_event);
1817 crm_trace("Callback invoked...");
1818
1819 event_free(st_event);
1820}
1821
1836static int
1837stonith_send_command(stonith_t * stonith, const char *op, xmlNode * data, xmlNode ** output_data,
1838 int call_options, int timeout)
1839{
1840 int rc = 0;
1841 int reply_id = -1;
1842
1843 xmlNode *op_msg = NULL;
1844 xmlNode *op_reply = NULL;
1845 stonith_private_t *native = NULL;
1846
1847 CRM_ASSERT(stonith && stonith->st_private && op);
1848 native = stonith->st_private;
1849
1850 if (output_data != NULL) {
1851 *output_data = NULL;
1852 }
1853
1854 if ((stonith->state == stonith_disconnected) || (native->token == NULL)) {
1855 return -ENOTCONN;
1856 }
1857
1858 /* Increment the call ID, which must be positive to avoid conflicting with
1859 * error codes. This shouldn't be a problem unless the client mucked with
1860 * it or the counter wrapped around.
1861 */
1862 stonith->call_id++;
1863 if (stonith->call_id < 1) {
1864 stonith->call_id = 1;
1865 }
1866
1867 op_msg = stonith_create_op(stonith->call_id, native->token, op, data, call_options);
1868 if (op_msg == NULL) {
1869 return -EINVAL;
1870 }
1871
1873 crm_trace("Sending %s message to fencer with timeout %ds", op, timeout);
1874
1875 if (data) {
1876 const char *delay_s = crm_element_value(data, F_STONITH_DELAY);
1877
1878 if (delay_s) {
1879 crm_xml_add(op_msg, F_STONITH_DELAY, delay_s);
1880 }
1881 }
1882
1883 {
1884 enum crm_ipc_flags ipc_flags = crm_ipc_flags_none;
1885
1886 if (call_options & st_opt_sync_call) {
1887 pcmk__set_ipc_flags(ipc_flags, "stonith command",
1889 }
1890 rc = crm_ipc_send(native->ipc, op_msg, ipc_flags,
1891 1000 * (timeout + 60), &op_reply);
1892 }
1893 free_xml(op_msg);
1894
1895 if (rc < 0) {
1896 crm_perror(LOG_ERR, "Couldn't perform %s operation (timeout=%ds): %d", op, timeout, rc);
1897 rc = -ECOMM;
1898 goto done;
1899 }
1900
1901 crm_log_xml_trace(op_reply, "Reply");
1902
1903 if (!(call_options & st_opt_sync_call)) {
1904 crm_trace("Async call %d, returning", stonith->call_id);
1905 free_xml(op_reply);
1906 return stonith->call_id;
1907 }
1908
1909 rc = pcmk_ok;
1910 crm_element_value_int(op_reply, F_STONITH_CALLID, &reply_id);
1911
1912 if (reply_id == stonith->call_id) {
1913 crm_trace("Synchronous reply %d received", reply_id);
1914
1915 if (crm_element_value_int(op_reply, F_STONITH_RC, &rc) != 0) {
1916 rc = -ENOMSG;
1917 }
1918
1919 if ((call_options & st_opt_discard_reply) || output_data == NULL) {
1920 crm_trace("Discarding reply");
1921
1922 } else {
1923 *output_data = op_reply;
1924 op_reply = NULL; /* Prevent subsequent free */
1925 }
1926
1927 } else if (reply_id <= 0) {
1928 crm_err("Received bad reply: No id set");
1929 crm_log_xml_err(op_reply, "Bad reply");
1930 free_xml(op_reply);
1931 rc = -ENOMSG;
1932
1933 } else {
1934 crm_err("Received bad reply: %d (wanted %d)", reply_id, stonith->call_id);
1935 crm_log_xml_err(op_reply, "Old reply");
1936 free_xml(op_reply);
1937 rc = -ENOMSG;
1938 }
1939
1940 done:
1941 if (crm_ipc_connected(native->ipc) == FALSE) {
1942 crm_err("Fencer disconnected");
1943 free(native->token); native->token = NULL;
1944 stonith->state = stonith_disconnected;
1945 }
1946
1947 free_xml(op_reply);
1948 return rc;
1949}
1950
1951/* Not used with mainloop */
1952bool
1954{
1955 gboolean stay_connected = TRUE;
1956 stonith_private_t *private = NULL;
1957
1958 CRM_ASSERT(st != NULL);
1959 private = st->st_private;
1960
1961 while (crm_ipc_ready(private->ipc)) {
1962
1963 if (crm_ipc_read(private->ipc) > 0) {
1964 const char *msg = crm_ipc_buffer(private->ipc);
1965
1966 stonith_dispatch_internal(msg, strlen(msg), st);
1967 }
1968
1969 if (crm_ipc_connected(private->ipc) == FALSE) {
1970 crm_err("Connection closed");
1971 stay_connected = FALSE;
1972 }
1973 }
1974
1975 return stay_connected;
1976}
1977
1978static int
1979stonith_api_free(stonith_t * stonith)
1980{
1981 int rc = pcmk_ok;
1982
1983 crm_trace("Destroying %p", stonith);
1984
1985 if (stonith->state != stonith_disconnected) {
1986 crm_trace("Disconnecting %p first", stonith);
1987 rc = stonith->cmds->disconnect(stonith);
1988 }
1989
1990 if (stonith->state == stonith_disconnected) {
1991 stonith_private_t *private = stonith->st_private;
1992
1993 crm_trace("Removing %d callbacks", g_hash_table_size(private->stonith_op_callback_table));
1994 g_hash_table_destroy(private->stonith_op_callback_table);
1995
1996 crm_trace("Destroying %d notification clients", g_list_length(private->notify_list));
1997 g_list_free_full(private->notify_list, free);
1998
1999 free(stonith->st_private);
2000 free(stonith->cmds);
2001 free(stonith);
2002
2003 } else {
2004 crm_err("Not free'ing active connection: %s (%d)", pcmk_strerror(rc), rc);
2005 }
2006
2007 return rc;
2008}
2009
2010void
2012{
2013 crm_trace("Destroying %p", stonith);
2014 if(stonith) {
2015 stonith->cmds->free(stonith);
2016 }
2017}
2018
2019static int
2020stonith_api_validate(stonith_t *st, int call_options, const char *rsc_id,
2021 const char *namespace_s, const char *agent,
2022 stonith_key_value_t *params, int timeout, char **output,
2023 char **error_output)
2024{
2025 /* Validation should be done directly via the agent, so we can get it from
2026 * stonith_admin when the cluster is not running, which is important for
2027 * higher-level tools.
2028 */
2029
2030 int rc = pcmk_ok;
2031
2032 /* Use a dummy node name in case the agent requires a target. We assume the
2033 * actual target doesn't matter for validation purposes (if in practice,
2034 * that is incorrect, we will need to allow the caller to pass the target).
2035 */
2036 const char *target = "node1";
2037 const char *host_arg = NULL;
2038
2039 GHashTable *params_table = pcmk__strkey_table(free, free);
2040
2041 // Convert parameter list to a hash table
2042 for (; params; params = params->next) {
2043 if (pcmk__str_eq(params->key, PCMK_STONITH_HOST_ARGUMENT,
2044 pcmk__str_casei)) {
2045 host_arg = params->value;
2046 }
2047 if (!pcmk_stonith_param(params->key)) {
2048 g_hash_table_insert(params_table, strdup(params->key),
2049 strdup(params->value));
2050 }
2051 }
2052
2053#if SUPPORT_CIBSECRETS
2054 rc = pcmk__substitute_secrets(rsc_id, params_table);
2055 if (rc != pcmk_rc_ok) {
2056 crm_warn("Could not replace secret parameters for validation of %s: %s",
2057 agent, pcmk_rc_str(rc));
2058 // rc is standard return value, don't return it in this function
2059 }
2060#endif
2061
2062 if (output) {
2063 *output = NULL;
2064 }
2065 if (error_output) {
2066 *error_output = NULL;
2067 }
2068
2069 switch (stonith_get_namespace(agent, namespace_s)) {
2070 case st_namespace_rhcs:
2071 rc = stonith__rhcs_validate(st, call_options, target, agent,
2072 params_table, host_arg, timeout,
2073 output, error_output);
2074 break;
2075
2076#if HAVE_STONITH_STONITH_H
2077 case st_namespace_lha:
2078 rc = stonith__lha_validate(st, call_options, target, agent,
2079 params_table, timeout, output,
2080 error_output);
2081 break;
2082#endif
2083
2084 default:
2085 rc = -EINVAL;
2086 errno = EINVAL;
2087 crm_perror(LOG_ERR,
2088 "Agent %s not found or does not support validation",
2089 agent);
2090 break;
2091 }
2092 g_hash_table_destroy(params_table);
2093 return rc;
2094}
2095
2096stonith_t *
2098{
2099 stonith_t *new_stonith = NULL;
2100 stonith_private_t *private = NULL;
2101
2102 new_stonith = calloc(1, sizeof(stonith_t));
2103 if (new_stonith == NULL) {
2104 return NULL;
2105 }
2106
2107 private = calloc(1, sizeof(stonith_private_t));
2108 if (private == NULL) {
2109 free(new_stonith);
2110 return NULL;
2111 }
2112 new_stonith->st_private = private;
2113
2114 private->stonith_op_callback_table = pcmk__intkey_table(stonith_destroy_op_callback);
2115 private->notify_list = NULL;
2116 private->notify_refcnt = 0;
2117 private->notify_deletes = FALSE;
2118
2119 new_stonith->call_id = 1;
2120 new_stonith->state = stonith_disconnected;
2121
2122 new_stonith->cmds = calloc(1, sizeof(stonith_api_operations_t));
2123 if (new_stonith->cmds == NULL) {
2124 free(new_stonith->st_private);
2125 free(new_stonith);
2126 return NULL;
2127 }
2128
2129/* *INDENT-OFF* */
2130 new_stonith->cmds->free = stonith_api_free;
2131 new_stonith->cmds->connect = stonith_api_signon;
2132 new_stonith->cmds->disconnect = stonith_api_signoff;
2133
2134 new_stonith->cmds->list = stonith_api_list;
2135 new_stonith->cmds->monitor = stonith_api_monitor;
2136 new_stonith->cmds->status = stonith_api_status;
2137 new_stonith->cmds->fence = stonith_api_fence;
2138 new_stonith->cmds->fence_with_delay = stonith_api_fence_with_delay;
2139 new_stonith->cmds->confirm = stonith_api_confirm;
2140 new_stonith->cmds->history = stonith_api_history;
2141
2142 new_stonith->cmds->list_agents = stonith_api_device_list;
2143 new_stonith->cmds->metadata = stonith_api_device_metadata;
2144
2145 new_stonith->cmds->query = stonith_api_query;
2146 new_stonith->cmds->remove_device = stonith_api_remove_device;
2147 new_stonith->cmds->register_device = stonith_api_register_device;
2148
2149 new_stonith->cmds->remove_level = stonith_api_remove_level;
2150 new_stonith->cmds->remove_level_full = stonith_api_remove_level_full;
2151 new_stonith->cmds->register_level = stonith_api_register_level;
2152 new_stonith->cmds->register_level_full = stonith_api_register_level_full;
2153
2154 new_stonith->cmds->remove_callback = stonith_api_del_callback;
2155 new_stonith->cmds->register_callback = stonith_api_add_callback;
2156 new_stonith->cmds->remove_notification = stonith_api_del_notification;
2157 new_stonith->cmds->register_notification = stonith_api_add_notification;
2158
2159 new_stonith->cmds->validate = stonith_api_validate;
2160/* *INDENT-ON* */
2161
2162 return new_stonith;
2163}
2164
2174int
2175stonith_api_connect_retry(stonith_t *st, const char *name, int max_attempts)
2176{
2177 int rc = -EINVAL; // if max_attempts is not positive
2178
2179 for (int attempt = 1; attempt <= max_attempts; attempt++) {
2180 rc = st->cmds->connect(st, name, NULL);
2181 if (rc == pcmk_ok) {
2182 return pcmk_ok;
2183 } else if (attempt < max_attempts) {
2184 crm_notice("Fencer connection attempt %d of %d failed (retrying in 2s): %s "
2185 CRM_XS " rc=%d",
2186 attempt, max_attempts, pcmk_strerror(rc), rc);
2187 sleep(2);
2188 }
2189 }
2190 crm_notice("Could not connect to fencer: %s " CRM_XS " rc=%d",
2191 pcmk_strerror(rc), rc);
2192 return rc;
2193}
2194
2196stonith_key_value_add(stonith_key_value_t * head, const char *key, const char *value)
2197{
2198 stonith_key_value_t *p, *end;
2199
2200 p = calloc(1, sizeof(stonith_key_value_t));
2201 if (key) {
2202 p->key = strdup(key);
2203 }
2204 if (value) {
2205 p->value = strdup(value);
2206 }
2207
2208 end = head;
2209 while (end && end->next) {
2210 end = end->next;
2211 }
2212
2213 if (end) {
2214 end->next = p;
2215 } else {
2216 head = p;
2217 }
2218
2219 return head;
2220}
2221
2222void
2224{
2226
2227 while (head) {
2228 p = head->next;
2229 if (keys) {
2230 free(head->key);
2231 }
2232 if (values) {
2233 free(head->value);
2234 }
2235 free(head);
2236 head = p;
2237 }
2238}
2239
2240#define api_log_open() openlog("stonith-api", LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON)
2241#define api_log(level, fmt, args...) syslog(level, "%s: "fmt, __func__, args)
2242
2243int
2244stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off)
2245{
2246 int rc = pcmk_ok;
2248 const char *action = off? "off" : "reboot";
2249
2250 api_log_open();
2251 if (st == NULL) {
2252 api_log(LOG_ERR, "API initialization failed, could not kick (%s) node %u/%s",
2253 action, nodeid, uname);
2254 return -EPROTO;
2255 }
2256
2257 rc = st->cmds->connect(st, "stonith-api", NULL);
2258 if (rc != pcmk_ok) {
2259 api_log(LOG_ERR, "Connection failed, could not kick (%s) node %u/%s : %s (%d)",
2260 action, nodeid, uname, pcmk_strerror(rc), rc);
2261 } else {
2262 char *name = (uname == NULL)? pcmk__itoa(nodeid) : strdup(uname);
2263 int opts = 0;
2264
2267 if ((uname == NULL) && (nodeid > 0)) {
2269 }
2270 rc = st->cmds->fence(st, opts, name, action, timeout, 0);
2271 free(name);
2272
2273 if (rc != pcmk_ok) {
2274 api_log(LOG_ERR, "Could not kick (%s) node %u/%s : %s (%d)",
2275 action, nodeid, uname, pcmk_strerror(rc), rc);
2276 } else {
2277 api_log(LOG_NOTICE, "Node %u/%s kicked: %s", nodeid, uname, action);
2278 }
2279 }
2280
2282 return rc;
2283}
2284
2285time_t
2286stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress)
2287{
2288 int rc = pcmk_ok;
2289 time_t when = 0;
2291 stonith_history_t *history = NULL, *hp = NULL;
2292
2293 if (st == NULL) {
2294 api_log(LOG_ERR, "Could not retrieve fence history for %u/%s: "
2295 "API initialization failed", nodeid, uname);
2296 return when;
2297 }
2298
2299 rc = st->cmds->connect(st, "stonith-api", NULL);
2300 if (rc != pcmk_ok) {
2301 api_log(LOG_NOTICE, "Connection failed: %s (%d)", pcmk_strerror(rc), rc);
2302 } else {
2303 int entries = 0;
2304 int progress = 0;
2305 int completed = 0;
2306 int opts = 0;
2307 char *name = (uname == NULL)? pcmk__itoa(nodeid) : strdup(uname);
2308
2310 if ((uname == NULL) && (nodeid > 0)) {
2312 }
2313 rc = st->cmds->history(st, opts, name, &history, 120);
2314 free(name);
2315
2316 for (hp = history; hp; hp = hp->next) {
2317 entries++;
2318 if (in_progress) {
2319 progress++;
2320 if (hp->state != st_done && hp->state != st_failed) {
2321 when = time(NULL);
2322 }
2323
2324 } else if (hp->state == st_done) {
2325 completed++;
2326 if (hp->completed > when) {
2327 when = hp->completed;
2328 }
2329 }
2330 }
2331
2332 stonith_history_free(history);
2333
2334 if(rc == pcmk_ok) {
2335 api_log(LOG_INFO, "Found %d entries for %u/%s: %d in progress, %d completed", entries, nodeid, uname, progress, completed);
2336 } else {
2337 api_log(LOG_ERR, "Could not retrieve fence history for %u/%s: %s (%d)", nodeid, uname, pcmk_strerror(rc), rc);
2338 }
2339 }
2340
2342
2343 if(when) {
2344 api_log(LOG_INFO, "Node %u/%s last kicked at: %ld", nodeid, uname, (long int)when);
2345 }
2346 return when;
2347}
2348
2349bool
2350stonith_agent_exists(const char *agent, int timeout)
2351{
2352 stonith_t *st = NULL;
2353 stonith_key_value_t *devices = NULL;
2354 stonith_key_value_t *dIter = NULL;
2355 bool rc = FALSE;
2356
2357 if (agent == NULL) {
2358 return rc;
2359 }
2360
2361 st = stonith_api_new();
2362 if (st == NULL) {
2363 crm_err("Could not list fence agents: API memory allocation failed");
2364 return FALSE;
2365 }
2366 st->cmds->list_agents(st, st_opt_sync_call, NULL, &devices, timeout == 0 ? 120 : timeout);
2367
2368 for (dIter = devices; dIter != NULL; dIter = dIter->next) {
2369 if (pcmk__str_eq(dIter->value, agent, pcmk__str_none)) {
2370 rc = TRUE;
2371 break;
2372 }
2373 }
2374
2375 stonith_key_value_freeall(devices, 1, 1);
2377 return rc;
2378}
2379
2380const char *
2382{
2383 if (action == NULL) {
2384 return "fencing";
2385 } else if (!strcmp(action, "on")) {
2386 return "unfencing";
2387 } else if (!strcmp(action, "off")) {
2388 return "turning off";
2389 } else {
2390 return action;
2391 }
2392}
2393
2402static void
2403parse_list_line(const char *line, int len, GList **output)
2404{
2405 size_t i = 0;
2406 size_t entry_start = 0;
2407
2408 /* Skip complaints about additional parameters device doesn't understand
2409 *
2410 * @TODO Document or eliminate the implied restriction of target names
2411 */
2412 if (strstr(line, "invalid") || strstr(line, "variable")) {
2413 crm_debug("Skipping list output line: %s", line);
2414 return;
2415 }
2416
2417 // Process line content, character by character
2418 for (i = 0; i <= len; i++) {
2419
2420 if (isspace(line[i]) || (line[i] == ',') || (line[i] == ';')
2421 || (line[i] == '\0')) {
2422 // We've found a separator (i.e. the end of an entry)
2423
2424 int rc = 0;
2425 char *entry = NULL;
2426
2427 if (i == entry_start) {
2428 // Skip leading and sequential separators
2429 entry_start = i + 1;
2430 continue;
2431 }
2432
2433 entry = calloc(i - entry_start + 1, sizeof(char));
2434 CRM_ASSERT(entry != NULL);
2435
2436 /* Read entry, stopping at first separator
2437 *
2438 * @TODO Document or eliminate these character restrictions
2439 */
2440 rc = sscanf(line + entry_start, "%[a-zA-Z0-9_-.]", entry);
2441 if (rc != 1) {
2442 crm_warn("Could not parse list output entry: %s "
2443 CRM_XS " entry_start=%d position=%d",
2444 line + entry_start, entry_start, i);
2445 free(entry);
2446
2447 } else if (pcmk__strcase_any_of(entry, "on", "off", NULL)) {
2448 /* Some agents print the target status in the list output,
2449 * though none are known now (the separate list-status command
2450 * is used for this, but it can also print "UNKNOWN"). To handle
2451 * this possibility, skip such entries.
2452 *
2453 * @TODO Document or eliminate the implied restriction of target
2454 * names.
2455 */
2456 free(entry);
2457
2458 } else {
2459 // We have a valid entry
2460 *output = g_list_append(*output, entry);
2461 }
2462 entry_start = i + 1;
2463 }
2464 }
2465}
2466
2488GList *
2489stonith__parse_targets(const char *target_spec)
2490{
2491 GList *targets = NULL;
2492
2493 if (target_spec != NULL) {
2494 size_t out_len = strlen(target_spec);
2495 size_t line_start = 0; // Starting index of line being processed
2496
2497 for (size_t i = 0; i <= out_len; ++i) {
2498 if ((target_spec[i] == '\n') || (target_spec[i] == '\0')
2499 || ((target_spec[i] == '\\') && (target_spec[i + 1] == 'n'))) {
2500 // We've reached the end of one line of output
2501
2502 int len = i - line_start;
2503
2504 if (len > 0) {
2505 char *line = strndup(target_spec + line_start, len);
2506
2507 line[len] = '\0'; // Because it might be a newline
2508 parse_list_line(line, len, &targets);
2509 free(line);
2510 }
2511 if (target_spec[i] == '\\') {
2512 ++i; // backslash-n takes up two positions
2513 }
2514 line_start = i + 1;
2515 }
2516 }
2517 }
2518 return targets;
2519}
2520
2528gboolean
2530{
2531 gboolean ret = FALSE;
2532
2533 for (stonith_history_t *prev_hp = top_history; prev_hp; prev_hp = prev_hp->next) {
2534 if (prev_hp == event) {
2535 break;
2536 }
2537
2538 if ((prev_hp->state == st_done) &&
2539 pcmk__str_eq(event->target, prev_hp->target, pcmk__str_casei) &&
2540 pcmk__str_eq(event->action, prev_hp->action, pcmk__str_casei) &&
2541 pcmk__str_eq(event->delegate, prev_hp->delegate, pcmk__str_casei) &&
2542 (event->completed < prev_hp->completed)) {
2543 ret = TRUE;
2544 break;
2545 }
2546 }
2547 return ret;
2548}
2549
2561{
2562 stonith_history_t *new = NULL, *pending = NULL, *hp, *np, *tmp;
2563
2564 for (hp = history; hp; ) {
2565 tmp = hp->next;
2566 if ((hp->state == st_done) || (hp->state == st_failed)) {
2567 /* sort into new */
2568 if ((!new) || (hp->completed > new->completed)) {
2569 hp->next = new;
2570 new = hp;
2571 } else {
2572 np = new;
2573 do {
2574 if ((!np->next) || (hp->completed > np->next->completed)) {
2575 hp->next = np->next;
2576 np->next = hp;
2577 break;
2578 }
2579 np = np->next;
2580 } while (1);
2581 }
2582 } else {
2583 /* put into pending */
2584 hp->next = pending;
2585 pending = hp;
2586 }
2587 hp = tmp;
2588 }
2589
2590 /* pending actions don't have a completed-stamp so make them go front */
2591 if (pending) {
2592 stonith_history_t *last_pending = pending;
2593
2594 while (last_pending->next) {
2595 last_pending = last_pending->next;
2596 }
2597
2598 last_pending->next = new;
2599 new = pending;
2600 }
2601 return new;
2602}
2603
2611const char *
2613{
2614 switch (state) {
2615 case st_query: return "querying";
2616 case st_exec: return "executing";
2617 case st_done: return "completed";
2618 case st_duplicate: return "duplicate";
2619 case st_failed: return "failed";
2620 }
2621 return "unknown";
2622}
2623
2626 bool (*matching_fn)(stonith_history_t *, void *),
2627 void *user_data)
2628{
2629 for (stonith_history_t *hp = history; hp; hp = hp->next) {
2630 if (matching_fn(hp, user_data)) {
2631 return hp;
2632 }
2633 }
2634
2635 return NULL;
2636}
2637
2638bool
2640{
2641 return history->state != st_failed && history->state != st_done;
2642}
2643
2644bool
2646{
2647 return history->state == GPOINTER_TO_INT(user_data);
2648}
2649
2650bool
2652{
2653 return history->state != GPOINTER_TO_INT(user_data);
2654}
2655
2656void
2657stonith__device_parameter_flags(uint32_t *device_flags, const char *device_name,
2658 xmlNode *metadata)
2659{
2660 xmlXPathObjectPtr xpath = NULL;
2661 int max = 0;
2662 int lpc = 0;
2663
2664 CRM_CHECK((device_flags != NULL) && (metadata != NULL), return);
2665
2666 xpath = xpath_search(metadata, "//parameter");
2667 max = numXpathResults(xpath);
2668
2669 if (max <= 0) {
2670 freeXpathObject(xpath);
2671 return;
2672 }
2673
2674 for (lpc = 0; lpc < max; lpc++) {
2675 const char *parameter = NULL;
2676 xmlNode *match = getXpathResult(xpath, lpc);
2677
2678 CRM_LOG_ASSERT(match != NULL);
2679 if (match == NULL) {
2680 continue;
2681 }
2682
2683 parameter = crm_element_value(match, "name");
2684
2685 if (pcmk__str_eq(parameter, "plug", pcmk__str_casei)) {
2686 stonith__set_device_flags(*device_flags, device_name,
2688
2689 } else if (pcmk__str_eq(parameter, "port", pcmk__str_casei)) {
2690 stonith__set_device_flags(*device_flags, device_name,
2692 }
2693 }
2694
2695 freeXpathObject(xpath);
2696}
2697
2698// Deprecated functions kept only for backward API compatibility
2699
2700const char *get_stonith_provider(const char *agent, const char *provider);
2701
2702const char *
2703get_stonith_provider(const char *agent, const char *provider)
2704{
2705 return stonith_namespace2text(stonith_get_namespace(agent, provider));
2706}
2707
2708// End deprecated API
#define PCMK_STONITH_HOST_ARGUMENT
Definition agents.h:32
bool pcmk_stonith_param(const char *param)
Check whether a given stonith parameter is handled by Pacemaker.
Definition agents.c:170
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
#define PCMK__FENCE_BINDIR
Definition config.h:513
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:146
#define CRM_META
Definition crm.h:78
#define F_STONITH_RC
Definition internal.h:105
#define F_STONITH_HISTORY_LIST
Definition internal.h:136
bool stonith__agent_is_rhcs(const char *agent)
Definition st_rhcs.c:233
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:244
#define F_STONITH_ORIGIN
Definition internal.h:135
#define T_STONITH_TIMEOUT_VALUE
Definition internal.h:151
@ 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:158
#define STONITH_OP_FENCE
Definition internal.h:159
#define F_STONITH_DELAY
Definition internal.h:109
#define F_STONITH_CLIENTID
Definition internal.h:97
#define F_STONITH_REMOTE_OP_ID
Definition internal.h:103
#define STONITH_OP_DEVICE_ADD
Definition internal.h:161
#define F_STONITH_DEVICE
Definition internal.h:142
#define F_STONITH_DATE
Definition internal.h:137
#define F_STONITH_TOLERANCE
Definition internal.h:108
#define STONITH_OP_EXEC
Definition internal.h:156
#define F_STONITH_TARGET
Definition internal.h:102
#define stonith__set_device_flags(device_flags, device_id, flags_to_set)
Definition internal.h:28
#define F_STONITH_NOTIFY_ACTIVATE
Definition internal.h:128
#define F_STONITH_NOTIFY_DEACTIVATE
Definition internal.h:129
#define F_STONITH_STATE
Definition internal.h:138
#define F_STONITH_CALLDATA
Definition internal.h:100
#define T_STONITH_NG
Definition internal.h:146
#define F_STONITH_CLIENTNAME
Definition internal.h:126
#define F_STONITH_DELEGATE
Definition internal.h:130
#define F_STONITH_ACTION
Definition internal.h:143
#define STONITH_OP_LEVEL_ADD
Definition internal.h:164
#define T_STONITH_NOTIFY
Definition internal.h:152
#define STONITH_OP_FENCE_HISTORY
Definition internal.h:163
struct stonith_action_s stonith_action_t
Definition internal.h:50
#define stonith__set_call_options(st_call_opts, call_for, flags_to_set)
Definition internal.h:35
#define STONITH_OP_LEVEL_DEL
Definition internal.h:165
#define F_STONITH_OPERATION
Definition internal.h:101
#define STONITH_ATTR_ACTION_OP
Definition internal.h:154
#define F_STONITH_CALLBACK_TOKEN
Definition internal.h:125
#define F_STONITH_CALLOPTS
Definition internal.h:98
#define STONITH_OP_DEVICE_DEL
Definition internal.h:162
int stonith__rhcs_metadata(const char *agent, int timeout, char **output)
Execute RHCS-compatible agent's meta-data action.
Definition st_rhcs.c:207
#define F_STONITH_CALLID
Definition internal.h:99
int stonith__list_rhcs_agents(stonith_key_value_t **devices)
Definition st_rhcs.c:33
#define F_STONITH_TIMEOUT
Definition internal.h:107
void crm_ipc_destroy(crm_ipc_t *client)
Definition ipc_client.c:875
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.
long crm_ipc_read(crm_ipc_t *client)
int crm_ipc_get_fd(crm_ipc_t *client)
Definition ipc_client.c:901
crm_ipc_flags
Definition ipc.h:144
@ crm_ipc_flags_none
Definition ipc.h:145
@ crm_ipc_client_response
Definition ipc.h:150
int crm_ipc_ready(crm_ipc_t *client)
Check whether an IPC connection is ready to be read.
Definition ipc_client.c:947
bool crm_ipc_connected(crm_ipc_t *client)
Definition ipc_client.c:915
bool crm_ipc_connect(crm_ipc_t *client)
Establish an IPC connection to a Pacemaker component.
Definition ipc_client.c:792
void crm_ipc_close(crm_ipc_t *client)
Definition ipc_client.c:862
const char * crm_ipc_buffer(crm_ipc_t *client)
struct crm_ipc_s crm_ipc_t
Definition ipc.h:162
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:745
#define pcmk__set_ipc_flags(ipc_flags, ipc_name, flags_to_set)
#define PCMK__IPC_TIMEOUT
#define CRM_TRACE_INIT_DATA(name)
Definition logging.h:143
#define crm_str(x)
Definition logging.h:376
#define crm_info(fmt, args...)
Definition logging.h:353
#define crm_warn(fmt, args...)
Definition logging.h:351
#define CRM_XS
Definition logging.h:54
#define crm_log_xml_debug(xml, text)
Definition logging.h:363
#define crm_log_output(level, prefix, output)
Definition logging.h:117
#define CRM_LOG_ASSERT(expr)
Definition logging.h:202
#define crm_log_xml_err(xml, text)
Definition logging.h:359
#define crm_notice(fmt, args...)
Definition logging.h:352
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition logging.h:301
#define CRM_CHECK(expr, failure_action)
Definition logging.h:218
#define crm_debug(fmt, args...)
Definition logging.h:355
#define crm_err(fmt, args...)
Definition logging.h:350
#define LOG_NEVER
Definition logging.h:46
#define crm_log_xml_trace(xml, text)
Definition logging.h:364
#define crm_log_xml_warn(xml, text)
Definition logging.h:360
#define crm_trace(fmt, args...)
Definition logging.h:356
#define LOG_TRACE
Definition logging.h:36
#define crm_log_xml_notice(xml, text)
Definition logging.h:361
Wrappers for and extensions to glib mainloop.
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
Definition mainloop.c:966
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:935
struct mainloop_io_s mainloop_io_t
Definition mainloop.h:32
#define G_PRIORITY_MEDIUM
Definition mainloop.h:181
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition mainloop.c:960
#define F_SUBTYPE
Definition msg_xml.h:59
#define XML_ATTR_STONITH_TARGET_ATTRIBUTE
Definition msg_xml.h:439
#define XML_TAG_FENCING_LEVEL
Definition msg_xml.h:434
#define F_XML_TAGNAME
Definition msg_xml.h:71
#define XML_ATTR_ID
Definition msg_xml.h:129
#define XML_ATTR_STONITH_INDEX
Definition msg_xml.h:435
#define XML_TAG_ATTRS
Definition msg_xml.h:205
#define F_TYPE
Definition msg_xml.h:63
#define XML_ATTR_STONITH_DEVICES
Definition msg_xml.h:440
#define XML_ATTR_STONITH_TARGET_PATTERN
Definition msg_xml.h:438
#define XML_ATTR_STONITH_TARGET_VALUE
Definition msg_xml.h:437
#define XML_ATTR_STONITH_TARGET
Definition msg_xml.h:436
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:530
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition nvpair.c:566
void hash2field(gpointer key, gpointer value, gpointer user_data)
Set XML attribute based on hash table entry.
Definition nvpair.c:786
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:432
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition nvpair.c:727
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:598
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:324
unsigned int timeout
Definition pcmk_fence.c:32
char * name
Definition pcmk_fence.c:31
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
int rc
Definition pcmk_fence.c:35
const char * target
Definition pcmk_fence.c:29
void log_action(unsigned int log_level, const char *pre_text, pe_action_t *action, gboolean details)
#define ENODATA
char * strndup(const char *str, size_t len)
#define ETIME
#define ECOMM
#define ENOTUNIQ
const char * pcmk_strerror(int rc)
Definition results.c:58
#define pcmk_err_generic
Definition results.h:70
#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:420
@ PCMK_OCF_TIMEOUT
Definition results.h:175
@ pcmk_rc_ok
Definition results.h:142
#define pcmk_ok
Definition results.h:67
@ SVC_ACTION_NON_BLOCKED
Definition services.h:115
gboolean services_action_sync(svc_action_t *op)
Definition services.c:918
#define PCMK_RESOURCE_CLASS_STONITH
Definition services.h:49
void services_action_free(svc_action_t *op)
Definition services.c:513
svc_action_t * services_action_create_generic(const char *exec, const char *args[])
Definition services.c:352
gboolean services_action_async_fork_notify(svc_action_t *op, void(*action_callback)(svc_action_t *), void(*action_fork_callback)(svc_action_t *))
Definition services.c:781
void stonith_api_delete(stonith_t *stonith)
Definition st_client.c:2011
const char * stonith_namespace2text(enum stonith_namespace st_namespace)
Get agent namespace name.
Definition st_client.c:157
time_t stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress)
Definition st_client.c:2286
stonith_key_value_t * stonith_key_value_add(stonith_key_value_t *head, const char *key, const char *value)
Definition st_client.c:2196
bool stonith__event_state_pending(stonith_history_t *history, void *user_data)
Definition st_client.c:2639
GList * stonith__parse_targets(const char *target_spec)
Definition st_client.c:2489
enum stonith_namespace stonith_get_namespace(const char *agent, const char *namespace_s)
Determine namespace of a fence agent.
Definition st_client.c:178
xmlNode * stonith_create_op(int call_id, const char *token, const char *op, xmlNode *data, int call_options)
Definition st_client.c:1204
void stonith_history_free(stonith_history_t *history)
Definition st_client.c:1158
void stonith__destroy_action(stonith_action_t *action)
Definition st_client.c:575
bool stonith__event_state_neq(stonith_history_t *history, void *user_data)
Definition st_client.c:2651
enum stonith_namespace stonith_text2namespace(const char *namespace_s)
Get agent namespace by name.
Definition st_client.c:131
void stonith__device_parameter_flags(uint32_t *device_flags, const char *device_name, xmlNode *metadata)
Definition st_client.c:2657
bool stonith__event_state_eq(stonith_history_t *history, void *user_data)
Definition st_client.c:2645
const char * stonith_action_str(const char *action)
Turn stonith action into a more readable string.
Definition st_client.c:2381
bool stonith_dispatch(stonith_t *st)
Definition st_client.c:1953
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:2175
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:2625
#define api_log(level, fmt, args...)
Definition st_client.c:2241
int stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off)
Definition st_client.c:2244
const char * get_stonith_provider(const char *agent, const char *provider)
Definition st_client.c:2703
stonith_action_t * stonith_action_create(const char *agent, const char *_action, const char *victim, uint32_t victim_nodeid, int timeout, GHashTable *device_args, GHashTable *port_map, const char *host_arg)
Definition st_client.c:635
int stonith_action_execute_async(stonith_action_t *action, void *userdata, void(*done)(GPid pid, int rc, const char *output, gpointer user_data), void(*fork_cb)(GPid pid, gpointer user_data))
Definition st_client.c:863
gboolean stonith__later_succeeded(stonith_history_t *event, stonith_history_t *top_history)
Definition st_client.c:2529
void stonith__action_result(stonith_action_t *action, int *rc, char **output, char **error_output)
Definition st_client.c:606
stonith_history_t * stonith__sort_history(stonith_history_t *history)
Definition st_client.c:2560
int stonith__execute(stonith_action_t *action)
Definition st_client.c:890
xmlNode * create_device_registration_xml(const char *id, enum stonith_namespace namespace, const char *agent, stonith_key_value_t *params, const char *rsc_provides)
Definition st_client.c:275
xmlNode * create_level_registration_xml(const char *node, const char *pattern, const char *attr, const char *value, int level, stonith_key_value_t *device_list)
Definition st_client.c:395
#define FAILURE_MAX_RETRIES
Definition st_client.c:633
int(* stonith_op_t)(const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **)
Definition st_client.c:108
stonith_t * stonith_api_new(void)
Definition st_client.c:2097
#define api_log_open()
Definition st_client.c:2240
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:2223
struct stonith_callback_client_s stonith_callback_client_t
bool stonith_agent_exists(const char *agent, int timeout)
Definition st_client.c:2350
void stonith_dump_pending_callbacks(stonith_t *stonith)
Definition st_client.c:1702
const char * stonith_op_state_str(enum op_state state)
Return string equivalent of an operation state value.
Definition st_client.c:2612
int stonith__lha_metadata(const char *agent, int timeout, char **output)
Definition st_lha.c:177
int stonith__list_lha_agents(stonith_key_value_t **devices)
Definition st_lha.c:108
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:276
bool stonith__agent_is_lha(const char *agent)
Determine namespace of a fence agent.
Definition st_lha.c:81
Fencing aka. STONITH.
#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
void pcmk__add_separated_word(char **list, size_t *len, const char *word, const char *separator)
Definition strings.c:702
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition strings.c:610
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:955
@ pcmk__str_none
@ pcmk__str_null_matches
@ pcmk__str_casei
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Dispatch function for an IPC connection used as mainloop source.
Definition mainloop.h:83
int(* fence_with_delay)(stonith_t *st, int options, const char *node, const char *action, int timeout, int tolerance, int delay)
Issue a fencing action against a node with requested fencing delay.
Definition stonith-ng.h:418
int(* free)(stonith_t *st)
Destroy the stonith api structure.
Definition stonith-ng.h:149
int(* register_level_full)(stonith_t *st, int options, const char *node, const char *pattern, const char *attr, const char *value, int level, stonith_key_value_t *device_list)
Register fencing level for specific node, node regex or attribute.
Definition stonith-ng.h:373
int(* remove_callback)(stonith_t *st, int call_id, bool all_callbacks)
Remove a registered callback for a given call id.
Definition stonith-ng.h:336
int(* register_level)(stonith_t *st, int options, const char *node, int level, stonith_key_value_t *device_list)
Register a fencing level containing the fencing devices to be used at that level for a specific node.
Definition stonith-ng.h:206
int(* status)(stonith_t *st, int options, const char *id, const char *port, int timeout)
Check to see if a local stonith device's port is reachable.
Definition stonith-ng.h:255
int(* metadata)(stonith_t *st, int options, const char *device, const char *provider, char **output, int timeout)
Get the metadata documentation for a resource.
Definition stonith-ng.h:217
int(* fence)(stonith_t *st, int options, const char *node, const char *action, int timeout, int tolerance)
Issue a fencing action against a node.
Definition stonith-ng.h:284
int(* register_notification)(stonith_t *st, const char *event, void(*notify)(stonith_t *st, stonith_event_t *e))
Definition stonith-ng.h:303
int(* connect)(stonith_t *st, const char *name, int *stonith_fd)
Connect to the local stonith daemon.
Definition stonith-ng.h:157
int(* register_callback)(stonith_t *st, int call_id, int timeout, int options, void *userdata, const char *callback_name, void(*callback)(stonith_t *st, stonith_callback_data_t *data))
Register a callback to receive the result of an asynchronous call.
Definition stonith-ng.h:325
int(* list_agents)(stonith_t *stonith, int call_options, const char *provider, stonith_key_value_t **devices, int timeout)
Retrieve a list of installed stonith agents.
Definition stonith-ng.h:230
int(* register_device)(stonith_t *st, int options, const char *id, const char *provider, const char *agent, stonith_key_value_t *params)
Register a stonith device with the local stonith daemon.
Definition stonith-ng.h:186
int(* remove_level)(stonith_t *st, int options, const char *node, int level)
Remove a fencing level for a specific node.
Definition stonith-ng.h:196
int(* list)(stonith_t *st, int options, const char *id, char **list_output, int timeout)
Retrieve string listing hosts and port assignments from a local stonith device.
Definition stonith-ng.h:239
int(* query)(stonith_t *st, int options, const char *node, stonith_key_value_t **devices, int timeout)
Retrieve a list of registered stonith devices.
Definition stonith-ng.h:266
int(* disconnect)(stonith_t *st)
Disconnect from the local stonith daemon.
Definition stonith-ng.h:165
int(* validate)(stonith_t *st, int call_options, const char *rsc_id, const char *namespace_s, const char *agent, stonith_key_value_t *params, int timeout, char **output, char **error_output)
Validate an arbitrary stonith device configuration.
Definition stonith-ng.h:396
int(* remove_level_full)(stonith_t *st, int options, const char *node, const char *pattern, const char *attr, const char *value, int level)
Remove fencing level for specific node, node regex or attribute.
Definition stonith-ng.h:353
int(* monitor)(stonith_t *st, int options, const char *id, int timeout)
Check to see if a local stonith device is reachable.
Definition stonith-ng.h:247
int(* history)(stonith_t *st, int options, const char *node, stonith_history_t **output, int timeout)
Retrieve a list of fencing operations that have occurred for a specific node.
Definition stonith-ng.h:301
int(* remove_notification)(stonith_t *st, const char *event)
Definition stonith-ng.h:306
int(* confirm)(stonith_t *st, int options, const char *node)
Manually confirm that a node is down.
Definition stonith-ng.h:293
int(* remove_device)(stonith_t *st, int options, const char *name)
Remove a registered stonith device with the local stonith daemon.
Definition stonith-ng.h:175
char * client_origin
Definition stonith-ng.h:133
struct stonith_history_s * next
Definition stonith-ng.h:112
struct stonith_key_value_s * next
Definition stonith-ng.h:101
enum stonith_state state
Definition stonith-ng.h:425
void * st_private
Definition stonith-ng.h:429
int call_timeout
Definition stonith-ng.h:428
stonith_api_operations_t * cmds
Definition stonith-ng.h:431
char * id
Definition services.h:120
void * cb_data
Definition services.h:153
char * agent
Definition services.h:127
char * standard
Definition services.h:125
enum svc_action_flags flags
Definition services.h:142
char * stderr_data
Definition services.h:144
GHashTable * params
Definition services.h:130
char * stdout_data
Definition services.h:145
int call_id
Definition internal.h:96
guint ref
Definition internal.h:98
int timeout
Definition internal.h:97
stonith_t * stonith
Definition st_client.c:105
Wrappers for and extensions to libxml2.
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:162
xmlNode * string2xml(const char *input)
Definition xml.c:868
void free_xml(xmlNode *child)
Definition xml.c:823
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition xml.c:696