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