pacemaker  3.0.0-d8340737c4
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  return st_namespace_invalid;
168 }
169 
170 gboolean
172 {
173  gboolean rv = FALSE;
174  stonith_t *stonith_api = st?st:stonith_api_new();
175  char *list = NULL;
176 
177  if(stonith_api) {
178  if (stonith_api->state == stonith_disconnected) {
179  int rc = stonith_api->cmds->connect(stonith_api, "stonith-api", NULL);
180 
181  if (rc != pcmk_ok) {
182  crm_err("Failed connecting to Stonith-API for watchdog-fencing-query.");
183  }
184  }
185 
186  if (stonith_api->state != stonith_disconnected) {
187  /* caveat!!!
188  * this might fail when when stonithd is just updating the device-list
189  * probably something we should fix as well for other api-calls */
190  int rc = stonith_api->cmds->list(stonith_api, st_opt_sync_call, STONITH_WATCHDOG_ID, &list, 0);
191  if ((rc != pcmk_ok) || (list == NULL)) {
192  /* due to the race described above it can happen that
193  * we drop in here - so as not to make remote nodes
194  * panic on that answer
195  */
196  if (rc == -ENODEV) {
197  crm_notice("Cluster does not have watchdog fencing device");
198  } else {
199  crm_warn("Could not check for watchdog fencing device: %s",
200  pcmk_strerror(rc));
201  }
202  } else if (list[0] == '\0') {
203  rv = TRUE;
204  } else {
205  GList *targets = stonith__parse_targets(list);
206  rv = pcmk__str_in_list(node, targets, pcmk__str_casei);
207  g_list_free_full(targets, free);
208  }
209  free(list);
210  if (!st) {
211  /* if we're provided the api we still might have done the
212  * connection - but let's assume the caller won't bother
213  */
214  stonith_api->cmds->disconnect(stonith_api);
215  }
216  }
217 
218  if (!st) {
219  stonith_api_delete(stonith_api);
220  }
221  } else {
222  crm_err("Stonith-API for watchdog-fencing-query couldn't be created.");
223  }
224  crm_trace("Pacemaker assumes node %s %sto do watchdog-fencing.",
225  node, rv?"":"not ");
226  return rv;
227 }
228 
229 gboolean
231 {
233 }
234 
235 /* when cycling through the list we don't want to delete items
236  so just mark them and when we know nobody is using the list
237  loop over it to remove the marked items
238  */
239 static void
240 foreach_notify_entry (stonith_private_t *private,
241  GFunc func,
242  gpointer user_data)
243 {
244  private->notify_refcnt++;
245  g_list_foreach(private->notify_list, func, user_data);
246  private->notify_refcnt--;
247  if ((private->notify_refcnt == 0) &&
248  private->notify_deletes) {
249  GList *list_item = private->notify_list;
250 
251  private->notify_deletes = FALSE;
252  while (list_item != NULL)
253  {
254  stonith_notify_client_t *list_client = list_item->data;
255  GList *next = g_list_next(list_item);
256 
257  if (list_client->delete) {
258  free(list_client);
259  private->notify_list =
260  g_list_delete_link(private->notify_list, list_item);
261  }
262  list_item = next;
263  }
264  }
265 }
266 
267 static void
268 stonith_connection_destroy(gpointer user_data)
269 {
270  stonith_t *stonith = user_data;
271  stonith_private_t *native = NULL;
272  struct notify_blob_s blob;
273 
274  crm_trace("Sending destroyed notification");
275  blob.stonith = stonith;
276  blob.xml = pcmk__xe_create(NULL, PCMK__XE_NOTIFY);
277 
278  native = stonith->st_private;
279  native->ipc = NULL;
280  native->source = NULL;
281 
282  free(native->token); native->token = NULL;
283  stonith->state = stonith_disconnected;
286 
287  foreach_notify_entry(native, stonith_send_notification, &blob);
288  pcmk__xml_free(blob.xml);
289 }
290 
291 xmlNode *
292 create_device_registration_xml(const char *id, enum stonith_namespace standard,
293  const char *agent,
294  const stonith_key_value_t *params,
295  const char *rsc_provides)
296 {
297  xmlNode *data = pcmk__xe_create(NULL, PCMK__XE_ST_DEVICE_ID);
298  xmlNode *args = pcmk__xe_create(data, PCMK__XE_ATTRIBUTES);
299 
300 #if HAVE_STONITH_STONITH_H
301  if (standard == st_namespace_any) {
302  standard = stonith_get_namespace(agent, NULL);
303  }
304  if (standard == st_namespace_lha) {
305  hash2field((gpointer) "plugin", (gpointer) agent, args);
306  agent = "fence_legacy";
307  }
308 #endif
309 
311  crm_xml_add(data, PCMK__XA_ST_ORIGIN, __func__);
312  crm_xml_add(data, PCMK_XA_AGENT, agent);
313  if ((standard != st_namespace_any) && (standard != st_namespace_invalid)) {
315  stonith_namespace2text(standard));
316  }
317  if (rsc_provides) {
318  crm_xml_add(data, PCMK__XA_RSC_PROVIDES, rsc_provides);
319  }
320 
321  for (; params; params = params->next) {
322  hash2field((gpointer) params->key, (gpointer) params->value, args);
323  }
324 
325  return data;
326 }
327 
328 static int
329 stonith_api_register_device(stonith_t *st, int call_options,
330  const char *id, const char *namespace_s,
331  const char *agent,
332  const stonith_key_value_t *params)
333 {
334  int rc = 0;
335  xmlNode *data = NULL;
336 
338  stonith_text2namespace(namespace_s),
339  agent, params, NULL);
340 
341  rc = stonith_send_command(st, STONITH_OP_DEVICE_ADD, data, NULL, call_options, 0);
343 
344  return rc;
345 }
346 
347 static int
348 stonith_api_remove_device(stonith_t * st, int call_options, const char *name)
349 {
350  int rc = 0;
351  xmlNode *data = NULL;
352 
354  crm_xml_add(data, PCMK__XA_ST_ORIGIN, __func__);
356  rc = stonith_send_command(st, STONITH_OP_DEVICE_DEL, data, NULL, call_options, 0);
358 
359  return rc;
360 }
361 
362 static int
363 stonith_api_remove_level_full(stonith_t *st, int options,
364  const char *node, const char *pattern,
365  const char *attr, const char *value, int level)
366 {
367  int rc = 0;
368  xmlNode *data = NULL;
369 
370  CRM_CHECK(node || pattern || (attr && value), return -EINVAL);
371 
373  crm_xml_add(data, PCMK__XA_ST_ORIGIN, __func__);
374 
375  if (node) {
377 
378  } else if (pattern) {
380 
381  } else {
384  }
385 
387  rc = stonith_send_command(st, STONITH_OP_LEVEL_DEL, data, NULL, options, 0);
389 
390  return rc;
391 }
392 
393 static int
394 stonith_api_remove_level(stonith_t * st, int options, const char *node, int level)
395 {
396  return stonith_api_remove_level_full(st, options, node,
397  NULL, NULL, NULL, level);
398 }
399 
415 xmlNode *
416 create_level_registration_xml(const char *node, const char *pattern,
417  const char *attr, const char *value,
418  int level, const stonith_key_value_t *device_list)
419 {
420  GString *list = NULL;
421  xmlNode *data;
422 
423  CRM_CHECK(node || pattern || (attr && value), return NULL);
424 
426 
427  crm_xml_add(data, PCMK__XA_ST_ORIGIN, __func__);
430 
431  if (node) {
433 
434  } else if (pattern) {
436 
437  } else {
440  }
441 
442  for (; device_list; device_list = device_list->next) {
443  pcmk__add_separated_word(&list, 1024, device_list->value, ",");
444  }
445 
446  if (list != NULL) {
447  crm_xml_add(data, PCMK_XA_DEVICES, (const char *) list->str);
448  g_string_free(list, TRUE);
449  }
450  return data;
451 }
452 
453 static int
454 stonith_api_register_level_full(stonith_t *st, int options, const char *node,
455  const char *pattern, const char *attr,
456  const char *value, int level,
457  const stonith_key_value_t *device_list)
458 {
459  int rc = 0;
460  xmlNode *data = create_level_registration_xml(node, pattern, attr, value,
461  level, device_list);
462  CRM_CHECK(data != NULL, return -EINVAL);
463 
464  rc = stonith_send_command(st, STONITH_OP_LEVEL_ADD, data, NULL, options, 0);
466 
467  return rc;
468 }
469 
470 static int
471 stonith_api_register_level(stonith_t * st, int options, const char *node, int level,
472  const stonith_key_value_t * device_list)
473 {
474  return stonith_api_register_level_full(st, options, node, NULL, NULL, NULL,
475  level, device_list);
476 }
477 
478 static int
479 stonith_api_device_list(stonith_t *stonith, int call_options,
480  const char *namespace_s, stonith_key_value_t **devices,
481  int timeout)
482 {
483  int count = 0;
484  enum stonith_namespace ns = stonith_text2namespace(namespace_s);
485 
486  if (devices == NULL) {
487  crm_err("Parameter error: stonith_api_device_list");
488  return -EFAULT;
489  }
490 
491 #if HAVE_STONITH_STONITH_H
492  // Include Linux-HA agents if requested
493  if ((ns == st_namespace_any) || (ns == st_namespace_lha)) {
494  count += stonith__list_lha_agents(devices);
495  }
496 #endif
497 
498  // Include Red Hat agents if requested
499  if ((ns == st_namespace_any) || (ns == st_namespace_rhcs)) {
500  count += stonith__list_rhcs_agents(devices);
501  }
502 
503  return count;
504 }
505 
506 // See stonith_api_operations_t:metadata() documentation
507 static int
508 stonith_api_device_metadata(stonith_t *stonith, int call_options,
509  const char *agent, const char *namespace_s,
510  char **output, int timeout_sec)
511 {
512  /* By executing meta-data directly, we can get it from stonith_admin when
513  * the cluster is not running, which is important for higher-level tools.
514  */
515 
516  enum stonith_namespace ns = stonith_get_namespace(agent, namespace_s);
517 
518  if (timeout_sec <= 0) {
519  timeout_sec = PCMK_DEFAULT_ACTION_TIMEOUT_MS;
520  }
521 
522  crm_trace("Looking up metadata for %s agent %s",
523  stonith_namespace2text(ns), agent);
524 
525  switch (ns) {
526  case st_namespace_rhcs:
527  return stonith__rhcs_metadata(agent, timeout_sec, output);
528 
529 #if HAVE_STONITH_STONITH_H
530  case st_namespace_lha:
531  return stonith__lha_metadata(agent, timeout_sec, output);
532 #endif
533 
534  default:
535  crm_err("Can't get fence agent '%s' meta-data: No such agent",
536  agent);
537  break;
538  }
539  return -ENODEV;
540 }
541 
542 static int
543 stonith_api_query(stonith_t * stonith, int call_options, const char *target,
544  stonith_key_value_t ** devices, int timeout)
545 {
546  int rc = 0, lpc = 0, max = 0;
547 
548  xmlNode *data = NULL;
549  xmlNode *output = NULL;
550  xmlXPathObjectPtr xpathObj = NULL;
551 
552  CRM_CHECK(devices != NULL, return -EINVAL);
553 
555  crm_xml_add(data, PCMK__XA_ST_ORIGIN, __func__);
558  rc = stonith_send_command(stonith, STONITH_OP_QUERY, data, &output, call_options, timeout);
559 
560  if (rc < 0) {
561  return rc;
562  }
563 
564  xpathObj = xpath_search(output, "//@agent");
565  if (xpathObj) {
566  max = numXpathResults(xpathObj);
567 
568  for (lpc = 0; lpc < max; lpc++) {
569  xmlNode *match = getXpathResult(xpathObj, lpc);
570 
571  CRM_LOG_ASSERT(match != NULL);
572  if(match != NULL) {
573  xmlChar *match_path = xmlGetNodePath(match);
574 
575  crm_info("%s[%d] = %s", "//@agent", lpc, match_path);
576  free(match_path);
577  *devices = stonith_key_value_add(*devices, NULL,
578  crm_element_value(match,
579  PCMK_XA_ID));
580  }
581  }
582 
583  freeXpathObject(xpathObj);
584  }
585 
586  pcmk__xml_free(output);
588  return max;
589 }
590 
603 static int
604 stonith_api_call(stonith_t *stonith, int call_options, const char *id,
605  const char *action, const char *target, int timeout_sec,
606  xmlNode **output)
607 {
608  int rc = 0;
609  xmlNode *data = NULL;
610 
612  crm_xml_add(data, PCMK__XA_ST_ORIGIN, __func__);
616 
617  rc = stonith_send_command(stonith, STONITH_OP_EXEC, data, output,
618  call_options, timeout_sec);
620 
621  return rc;
622 }
623 
624 static int
625 stonith_api_list(stonith_t * stonith, int call_options, const char *id, char **list_info,
626  int timeout)
627 {
628  int rc;
629  xmlNode *output = NULL;
630 
631  rc = stonith_api_call(stonith, call_options, id, PCMK_ACTION_LIST, NULL,
632  timeout, &output);
633 
634  if (output && list_info) {
635  const char *list_str;
636 
637  list_str = crm_element_value(output, PCMK__XA_ST_OUTPUT);
638 
639  if (list_str) {
640  *list_info = strdup(list_str);
641  }
642  }
643 
644  if (output) {
645  pcmk__xml_free(output);
646  }
647 
648  return rc;
649 }
650 
651 static int
652 stonith_api_monitor(stonith_t * stonith, int call_options, const char *id, int timeout)
653 {
654  return stonith_api_call(stonith, call_options, id, PCMK_ACTION_MONITOR,
655  NULL, timeout, NULL);
656 }
657 
658 static int
659 stonith_api_status(stonith_t * stonith, int call_options, const char *id, const char *port,
660  int timeout)
661 {
662  return stonith_api_call(stonith, call_options, id, PCMK_ACTION_STATUS, port,
663  timeout, NULL);
664 }
665 
666 static int
667 stonith_api_fence_with_delay(stonith_t * stonith, int call_options, const char *node,
668  const char *action, int timeout, int tolerance, int delay)
669 {
670  int rc = 0;
671  xmlNode *data = NULL;
672 
673  data = pcmk__xe_create(NULL, __func__);
679 
680  rc = stonith_send_command(stonith, STONITH_OP_FENCE, data, NULL, call_options, timeout);
682 
683  return rc;
684 }
685 
686 static int
687 stonith_api_fence(stonith_t * stonith, int call_options, const char *node, const char *action,
688  int timeout, int tolerance)
689 {
690  return stonith_api_fence_with_delay(stonith, call_options, node, action,
691  timeout, tolerance, 0);
692 }
693 
694 static int
695 stonith_api_confirm(stonith_t * stonith, int call_options, const char *target)
696 {
698  return stonith_api_fence(stonith, call_options, target, PCMK_ACTION_OFF, 0,
699  0);
700 }
701 
702 static int
703 stonith_api_history(stonith_t * stonith, int call_options, const char *node,
704  stonith_history_t ** history, int timeout)
705 {
706  int rc = 0;
707  xmlNode *data = NULL;
708  xmlNode *output = NULL;
709  stonith_history_t *last = NULL;
710 
711  *history = NULL;
712 
713  if (node) {
714  data = pcmk__xe_create(NULL, __func__);
716  }
717 
718  stonith__set_call_options(call_options, node, st_opt_sync_call);
719  rc = stonith_send_command(stonith, STONITH_OP_FENCE_HISTORY, data, &output,
720  call_options, timeout);
722 
723  if (rc == 0) {
724  xmlNode *op = NULL;
725  xmlNode *reply = get_xpath_object("//" PCMK__XE_ST_HISTORY, output,
726  LOG_NEVER);
727 
728  for (op = pcmk__xe_first_child(reply, NULL, NULL, NULL); op != NULL;
729  op = pcmk__xe_next(op, NULL)) {
730  stonith_history_t *kvp;
731  long long completed;
732  long long completed_nsec = 0L;
733 
734  kvp = pcmk__assert_alloc(1, sizeof(stonith_history_t));
740  crm_element_value_ll(op, PCMK__XA_ST_DATE, &completed);
741  kvp->completed = (time_t) completed;
742  crm_element_value_ll(op, PCMK__XA_ST_DATE_NSEC, &completed_nsec);
743  kvp->completed_nsec = completed_nsec;
746 
747  if (last) {
748  last->next = kvp;
749  } else {
750  *history = kvp;
751  }
752  last = kvp;
753  }
754  }
755 
756  pcmk__xml_free(output);
757 
758  return rc;
759 }
760 
762 {
763  stonith_history_t *hp, *hp_old;
764 
765  for (hp = history; hp; hp_old = hp, hp = hp->next, free(hp_old)) {
766  free(hp->target);
767  free(hp->action);
768  free(hp->origin);
769  free(hp->delegate);
770  free(hp->client);
771  free(hp->exit_reason);
772  }
773 }
774 
775 static gint
776 stonithlib_GCompareFunc(gconstpointer a, gconstpointer b)
777 {
778  int rc = 0;
779  const stonith_notify_client_t *a_client = a;
780  const stonith_notify_client_t *b_client = b;
781 
782  if (a_client->delete || b_client->delete) {
783  /* make entries marked for deletion not findable */
784  return -1;
785  }
786  CRM_CHECK(a_client->event != NULL && b_client->event != NULL, return 0);
787  rc = strcmp(a_client->event, b_client->event);
788  if (rc == 0) {
789  if (a_client->notify == NULL || b_client->notify == NULL) {
790  return 0;
791 
792  } else if (a_client->notify == b_client->notify) {
793  return 0;
794 
795  } else if (((long)a_client->notify) < ((long)b_client->notify)) {
796  crm_err("callbacks for %s are not equal: %p vs. %p",
797  a_client->event, a_client->notify, b_client->notify);
798  return -1;
799  }
800  crm_err("callbacks for %s are not equal: %p vs. %p",
801  a_client->event, a_client->notify, b_client->notify);
802  return 1;
803  }
804  return rc;
805 }
806 
807 xmlNode *
808 stonith_create_op(int call_id, const char *token, const char *op, xmlNode * data, int call_options)
809 {
810  xmlNode *op_msg = NULL;
811 
812  CRM_CHECK(token != NULL, return NULL);
813 
816  crm_xml_add(op_msg, PCMK__XA_ST_OP, op);
817  crm_xml_add_int(op_msg, PCMK__XA_ST_CALLID, call_id);
818  crm_trace("Sending call options: %.8lx, %d", (long)call_options, call_options);
819  crm_xml_add_int(op_msg, PCMK__XA_ST_CALLOPT, call_options);
820 
821  if (data != NULL) {
822  xmlNode *wrapper = pcmk__xe_create(op_msg, PCMK__XE_ST_CALLDATA);
823 
824  pcmk__xml_copy(wrapper, data);
825  }
826 
827  return op_msg;
828 }
829 
830 static void
831 stonith_destroy_op_callback(gpointer data)
832 {
834 
835  if (blob->timer && blob->timer->ref > 0) {
836  g_source_remove(blob->timer->ref);
837  }
838  free(blob->timer);
839  free(blob);
840 }
841 
842 static int
843 stonith_api_signoff(stonith_t * stonith)
844 {
845  stonith_private_t *native = stonith->st_private;
846 
847  crm_debug("Disconnecting from the fencer");
848 
849  if (native->source != NULL) {
850  /* Attached to mainloop */
851  mainloop_del_ipc_client(native->source);
852  native->source = NULL;
853  native->ipc = NULL;
854 
855  } else if (native->ipc) {
856  /* Not attached to mainloop */
857  crm_ipc_t *ipc = native->ipc;
858 
859  native->ipc = NULL;
860  crm_ipc_close(ipc);
861  crm_ipc_destroy(ipc);
862  }
863 
864  free(native->token); native->token = NULL;
865  stonith->state = stonith_disconnected;
866  return pcmk_ok;
867 }
868 
869 static int
870 stonith_api_del_callback(stonith_t * stonith, int call_id, bool all_callbacks)
871 {
872  stonith_private_t *private = stonith->st_private;
873 
874  if (all_callbacks) {
875  private->op_callback = NULL;
876  g_hash_table_destroy(private->stonith_op_callback_table);
877  private->stonith_op_callback_table = pcmk__intkey_table(stonith_destroy_op_callback);
878 
879  } else if (call_id == 0) {
880  private->op_callback = NULL;
881 
882  } else {
883  pcmk__intkey_table_remove(private->stonith_op_callback_table, call_id);
884  }
885  return pcmk_ok;
886 }
887 
899 static void
900 invoke_fence_action_callback(stonith_t *st, int call_id,
902  void *userdata,
903  void (*callback) (stonith_t *st,
905 {
906  stonith_callback_data_t data = { 0, };
907 
908  data.call_id = call_id;
910  data.userdata = userdata;
911  data.opaque = (void *) result;
912 
913  callback(st, &data);
914 }
915 
927 static void
928 invoke_registered_callbacks(stonith_t *stonith, const xmlNode *msg, int call_id)
929 {
930  stonith_private_t *private = NULL;
931  stonith_callback_client_t *cb_info = NULL;
933 
934  CRM_CHECK(stonith != NULL, return);
935  CRM_CHECK(stonith->st_private != NULL, return);
936 
937  private = stonith->st_private;
938 
939  if (msg == NULL) {
940  // Fencer didn't reply in time
942  "Fencer accepted request but did not reply in time");
943  CRM_LOG_ASSERT(call_id > 0);
944 
945  } else {
946  // We have the fencer reply
947  if ((crm_element_value_int(msg, PCMK__XA_ST_CALLID, &call_id) != 0)
948  || (call_id <= 0)) {
949  crm_log_xml_warn(msg, "Bad fencer reply");
950  }
952  }
953 
954  if (call_id > 0) {
955  cb_info = pcmk__intkey_table_lookup(private->stonith_op_callback_table,
956  call_id);
957  }
958 
959  if ((cb_info != NULL) && (cb_info->callback != NULL)
960  && (pcmk__result_ok(&result) || !(cb_info->only_success))) {
961  crm_trace("Invoking callback %s for call %d",
962  pcmk__s(cb_info->id, "without ID"), call_id);
963  invoke_fence_action_callback(stonith, call_id, &result,
964  cb_info->user_data, cb_info->callback);
965 
966  } else if ((private->op_callback == NULL) && !pcmk__result_ok(&result)) {
967  crm_warn("Fencing action without registered callback failed: %d (%s%s%s)",
969  pcmk_exec_status_str(result.execution_status),
970  ((result.exit_reason == NULL)? "" : ": "),
971  ((result.exit_reason == NULL)? "" : result.exit_reason));
972  crm_log_xml_debug(msg, "Failed fence update");
973  }
974 
975  if (private->op_callback != NULL) {
976  crm_trace("Invoking global callback for call %d", call_id);
977  invoke_fence_action_callback(stonith, call_id, &result, NULL,
978  private->op_callback);
979  }
980 
981  if (cb_info != NULL) {
982  stonith_api_del_callback(stonith, call_id, FALSE);
983  }
985 }
986 
987 static gboolean
988 stonith_async_timeout_handler(gpointer data)
989 {
990  struct timer_rec_s *timer = data;
991 
992  crm_err("Async call %d timed out after %dms", timer->call_id, timer->timeout);
993  invoke_registered_callbacks(timer->stonith, NULL, timer->call_id);
994 
995  /* Always return TRUE, never remove the handler
996  * We do that in stonith_del_callback()
997  */
998  return TRUE;
999 }
1000 
1001 static void
1002 set_callback_timeout(stonith_callback_client_t * callback, stonith_t * stonith, int call_id,
1003  int timeout)
1004 {
1005  struct timer_rec_s *async_timer = callback->timer;
1006 
1007  if (timeout <= 0) {
1008  return;
1009  }
1010 
1011  if (!async_timer) {
1012  async_timer = pcmk__assert_alloc(1, sizeof(struct timer_rec_s));
1013  callback->timer = async_timer;
1014  }
1015 
1016  async_timer->stonith = stonith;
1017  async_timer->call_id = call_id;
1018  /* Allow a fair bit of grace to allow the server to tell us of a timeout
1019  * This is only a fallback
1020  */
1021  async_timer->timeout = (timeout + 60) * 1000;
1022  if (async_timer->ref) {
1023  g_source_remove(async_timer->ref);
1024  }
1025  async_timer->ref =
1026  pcmk__create_timer(async_timer->timeout, stonith_async_timeout_handler,
1027  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  pcmk__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  pcmk__xml_free(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  pcmk__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  QB_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  pcmk__xml_free(reply);
1182  pcmk__xml_free(hello);
1183  }
1184 
1185  if (rc != pcmk_ok) {
1186  crm_debug("Connection attempt to fencer by %s failed: %s "
1187  QB_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  pcmk__xml_free(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->operation);
1478  free(event->origin);
1479  free(event->action);
1480  free(event->target);
1481  free(event->executioner);
1482  free(event->device);
1483  free(event->client_origin);
1484  pcmk__reset_result(&event_private->result);
1485  free(event->opaque);
1486  free(event);
1487 }
1488 
1489 static void
1490 stonith_send_notification(gpointer data, gpointer user_data)
1491 {
1492  struct notify_blob_s *blob = user_data;
1493  stonith_notify_client_t *entry = data;
1494  stonith_event_t *st_event = NULL;
1495  const char *event = NULL;
1496 
1497  if (blob->xml == NULL) {
1498  crm_warn("Skipping callback - NULL message");
1499  return;
1500  }
1501 
1502  event = crm_element_value(blob->xml, PCMK__XA_SUBT);
1503 
1504  if (entry == NULL) {
1505  crm_warn("Skipping callback - NULL callback client");
1506  return;
1507 
1508  } else if (entry->delete) {
1509  crm_trace("Skipping callback - marked for deletion");
1510  return;
1511 
1512  } else if (entry->notify == NULL) {
1513  crm_warn("Skipping callback - NULL callback");
1514  return;
1515 
1516  } else if (!pcmk__str_eq(entry->event, event, pcmk__str_none)) {
1517  crm_trace("Skipping callback - event mismatch %p/%s vs. %s", entry, entry->event, event);
1518  return;
1519  }
1520 
1521  st_event = xml_to_event(blob->xml);
1522 
1523  crm_trace("Invoking callback for %p/%s event...", entry, event);
1524  entry->notify(blob->stonith, st_event);
1525  crm_trace("Callback invoked...");
1526 
1527  event_free(st_event);
1528 }
1529 
1544 static int
1545 stonith_send_command(stonith_t * stonith, const char *op, xmlNode * data, xmlNode ** output_data,
1546  int call_options, int timeout)
1547 {
1548  int rc = 0;
1549  int reply_id = -1;
1550 
1551  xmlNode *op_msg = NULL;
1552  xmlNode *op_reply = NULL;
1553  stonith_private_t *native = NULL;
1554 
1555  pcmk__assert((stonith != NULL) && (stonith->st_private != NULL)
1556  && (op != NULL));
1557  native = stonith->st_private;
1558 
1559  if (output_data != NULL) {
1560  *output_data = NULL;
1561  }
1562 
1563  if ((stonith->state == stonith_disconnected) || (native->token == NULL)) {
1564  return -ENOTCONN;
1565  }
1566 
1567  /* Increment the call ID, which must be positive to avoid conflicting with
1568  * error codes. This shouldn't be a problem unless the client mucked with
1569  * it or the counter wrapped around.
1570  */
1571  stonith->call_id++;
1572  if (stonith->call_id < 1) {
1573  stonith->call_id = 1;
1574  }
1575 
1576  op_msg = stonith_create_op(stonith->call_id, native->token, op, data, call_options);
1577  if (op_msg == NULL) {
1578  return -EINVAL;
1579  }
1580 
1582  crm_trace("Sending %s message to fencer with timeout %ds", op, timeout);
1583 
1584  if (data) {
1585  const char *delay_s = crm_element_value(data, PCMK__XA_ST_DELAY);
1586 
1587  if (delay_s) {
1588  crm_xml_add(op_msg, PCMK__XA_ST_DELAY, delay_s);
1589  }
1590  }
1591 
1592  {
1593  enum crm_ipc_flags ipc_flags = crm_ipc_flags_none;
1594 
1595  if (call_options & st_opt_sync_call) {
1596  pcmk__set_ipc_flags(ipc_flags, "stonith command",
1598  }
1599  rc = crm_ipc_send(native->ipc, op_msg, ipc_flags,
1600  1000 * (timeout + 60), &op_reply);
1601  }
1602  pcmk__xml_free(op_msg);
1603 
1604  if (rc < 0) {
1605  crm_perror(LOG_ERR, "Couldn't perform %s operation (timeout=%ds): %d", op, timeout, rc);
1606  rc = -ECOMM;
1607  goto done;
1608  }
1609 
1610  crm_log_xml_trace(op_reply, "Reply");
1611 
1612  if (!(call_options & st_opt_sync_call)) {
1613  crm_trace("Async call %d, returning", stonith->call_id);
1614  pcmk__xml_free(op_reply);
1615  return stonith->call_id;
1616  }
1617 
1618  crm_element_value_int(op_reply, PCMK__XA_ST_CALLID, &reply_id);
1619 
1620  if (reply_id == stonith->call_id) {
1622 
1623  crm_trace("Synchronous reply %d received", reply_id);
1624 
1625  stonith__xe_get_result(op_reply, &result);
1628 
1629  if ((call_options & st_opt_discard_reply) || output_data == NULL) {
1630  crm_trace("Discarding reply");
1631 
1632  } else {
1633  *output_data = op_reply;
1634  op_reply = NULL; /* Prevent subsequent free */
1635  }
1636 
1637  } else if (reply_id <= 0) {
1638  crm_err("Received bad reply: No id set");
1639  crm_log_xml_err(op_reply, "Bad reply");
1640  pcmk__xml_free(op_reply);
1641  op_reply = NULL;
1642  rc = -ENOMSG;
1643 
1644  } else {
1645  crm_err("Received bad reply: %d (wanted %d)", reply_id, stonith->call_id);
1646  crm_log_xml_err(op_reply, "Old reply");
1647  pcmk__xml_free(op_reply);
1648  op_reply = NULL;
1649  rc = -ENOMSG;
1650  }
1651 
1652  done:
1653  if (!crm_ipc_connected(native->ipc)) {
1654  crm_err("Fencer disconnected");
1655  free(native->token); native->token = NULL;
1656  stonith->state = stonith_disconnected;
1657  }
1658 
1659  pcmk__xml_free(op_reply);
1660  return rc;
1661 }
1662 
1663 /* Not used with mainloop */
1664 bool
1666 {
1667  gboolean stay_connected = TRUE;
1668  stonith_private_t *private = NULL;
1669 
1670  pcmk__assert(st != NULL);
1671  private = st->st_private;
1672 
1673  while (crm_ipc_ready(private->ipc)) {
1674 
1675  if (crm_ipc_read(private->ipc) > 0) {
1676  const char *msg = crm_ipc_buffer(private->ipc);
1677 
1678  stonith_dispatch_internal(msg, strlen(msg), st);
1679  }
1680 
1681  if (!crm_ipc_connected(private->ipc)) {
1682  crm_err("Connection closed");
1683  stay_connected = FALSE;
1684  }
1685  }
1686 
1687  return stay_connected;
1688 }
1689 
1690 static int
1691 stonith_api_free(stonith_t * stonith)
1692 {
1693  int rc = pcmk_ok;
1694 
1695  crm_trace("Destroying %p", stonith);
1696 
1697  if (stonith->state != stonith_disconnected) {
1698  crm_trace("Unregistering notifications and disconnecting %p first",
1699  stonith);
1700  stonith->cmds->remove_notification(stonith, NULL);
1701  rc = stonith->cmds->disconnect(stonith);
1702  }
1703 
1704  if (stonith->state == stonith_disconnected) {
1705  stonith_private_t *private = stonith->st_private;
1706 
1707  crm_trace("Removing %d callbacks", g_hash_table_size(private->stonith_op_callback_table));
1708  g_hash_table_destroy(private->stonith_op_callback_table);
1709 
1710  crm_trace("Destroying %d notification clients", g_list_length(private->notify_list));
1711  g_list_free_full(private->notify_list, free);
1712 
1713  free(stonith->st_private);
1714  free(stonith->cmds);
1715  free(stonith);
1716 
1717  } else {
1718  crm_err("Not free'ing active connection: %s (%d)", pcmk_strerror(rc), rc);
1719  }
1720 
1721  return rc;
1722 }
1723 
1724 void
1726 {
1727  crm_trace("Destroying %p", stonith);
1728  if(stonith) {
1729  stonith->cmds->free(stonith);
1730  }
1731 }
1732 
1733 static gboolean
1734 is_stonith_param(gpointer key, gpointer value, gpointer user_data)
1735 {
1736  return pcmk_stonith_param(key);
1737 }
1738 
1739 int
1740 stonith__validate(stonith_t *st, int call_options, const char *rsc_id,
1741  const char *namespace_s, const char *agent,
1742  GHashTable *params, int timeout_sec, char **output,
1743  char **error_output)
1744 {
1745  int rc = pcmk_rc_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  char *host_arg = NULL;
1753 
1754  if (params != NULL) {
1755  host_arg = pcmk__str_copy(g_hash_table_lookup(params, PCMK_STONITH_HOST_ARGUMENT));
1756 
1757  /* Remove special stonith params from the table before doing anything else */
1758  g_hash_table_foreach_remove(params, is_stonith_param, NULL);
1759  }
1760 
1761 #if PCMK__ENABLE_CIBSECRETS
1762  rc = pcmk__substitute_secrets(rsc_id, params);
1763  if (rc != pcmk_rc_ok) {
1764  crm_warn("Could not replace secret parameters for validation of %s: %s",
1765  agent, pcmk_rc_str(rc));
1766  // rc is standard return value, don't return it in this function
1767  }
1768 #endif
1769 
1770  if (output) {
1771  *output = NULL;
1772  }
1773  if (error_output) {
1774  *error_output = NULL;
1775  }
1776 
1777  if (timeout_sec <= 0) {
1778  timeout_sec = PCMK_DEFAULT_ACTION_TIMEOUT_MS;
1779  }
1780 
1781  switch (stonith_get_namespace(agent, namespace_s)) {
1782  case st_namespace_rhcs:
1783  rc = stonith__rhcs_validate(st, call_options, target, agent,
1784  params, host_arg, timeout_sec,
1785  output, error_output);
1786  rc = pcmk_legacy2rc(rc);
1787  break;
1788 
1789 #if HAVE_STONITH_STONITH_H
1790  case st_namespace_lha:
1791  rc = stonith__lha_validate(st, call_options, target, agent,
1792  params, timeout_sec, output,
1793  error_output);
1794  rc = pcmk_legacy2rc(rc);
1795  break;
1796 #endif
1797 
1798  case st_namespace_invalid:
1799  errno = ENOENT;
1800  rc = errno;
1801 
1802  if (error_output) {
1803  *error_output = crm_strdup_printf("Agent %s not found", agent);
1804  } else {
1805  crm_err("Agent %s not found", agent);
1806  }
1807 
1808  break;
1809 
1810  default:
1811  errno = EOPNOTSUPP;
1812  rc = errno;
1813 
1814  if (error_output) {
1815  *error_output = crm_strdup_printf("Agent %s does not support validation",
1816  agent);
1817  } else {
1818  crm_err("Agent %s does not support validation", agent);
1819  }
1820 
1821  break;
1822  }
1823 
1824  free(host_arg);
1825  return rc;
1826 }
1827 
1828 static int
1829 stonith_api_validate(stonith_t *st, int call_options, const char *rsc_id,
1830  const char *namespace_s, const char *agent,
1831  const stonith_key_value_t *params, int timeout_sec,
1832  char **output, char **error_output)
1833 {
1834  /* Validation should be done directly via the agent, so we can get it from
1835  * stonith_admin when the cluster is not running, which is important for
1836  * higher-level tools.
1837  */
1838 
1839  int rc = pcmk_ok;
1840 
1841  GHashTable *params_table = pcmk__strkey_table(free, free);
1842 
1843  // Convert parameter list to a hash table
1844  for (; params; params = params->next) {
1845  if (!pcmk_stonith_param(params->key)) {
1846  pcmk__insert_dup(params_table, params->key, params->value);
1847  }
1848  }
1849 
1850  rc = stonith__validate(st, call_options, rsc_id, namespace_s, agent,
1851  params_table, timeout_sec, output, error_output);
1852 
1853  g_hash_table_destroy(params_table);
1854  return rc;
1855 }
1856 
1857 stonith_t *
1859 {
1860  stonith_t *new_stonith = NULL;
1861  stonith_private_t *private = NULL;
1862 
1863  new_stonith = calloc(1, sizeof(stonith_t));
1864  if (new_stonith == NULL) {
1865  return NULL;
1866  }
1867 
1868  private = calloc(1, sizeof(stonith_private_t));
1869  if (private == NULL) {
1870  free(new_stonith);
1871  return NULL;
1872  }
1873  new_stonith->st_private = private;
1874 
1875  private->stonith_op_callback_table = pcmk__intkey_table(stonith_destroy_op_callback);
1876  private->notify_list = NULL;
1877  private->notify_refcnt = 0;
1878  private->notify_deletes = FALSE;
1879 
1880  new_stonith->call_id = 1;
1881  new_stonith->state = stonith_disconnected;
1882 
1883  new_stonith->cmds = calloc(1, sizeof(stonith_api_operations_t));
1884  if (new_stonith->cmds == NULL) {
1885  free(new_stonith->st_private);
1886  free(new_stonith);
1887  return NULL;
1888  }
1889 
1890 /* *INDENT-OFF* */
1891  new_stonith->cmds->free = stonith_api_free;
1892  new_stonith->cmds->connect = stonith_api_signon;
1893  new_stonith->cmds->disconnect = stonith_api_signoff;
1894 
1895  new_stonith->cmds->list = stonith_api_list;
1896  new_stonith->cmds->monitor = stonith_api_monitor;
1897  new_stonith->cmds->status = stonith_api_status;
1898  new_stonith->cmds->fence = stonith_api_fence;
1899  new_stonith->cmds->fence_with_delay = stonith_api_fence_with_delay;
1900  new_stonith->cmds->confirm = stonith_api_confirm;
1901  new_stonith->cmds->history = stonith_api_history;
1902 
1903  new_stonith->cmds->list_agents = stonith_api_device_list;
1904  new_stonith->cmds->metadata = stonith_api_device_metadata;
1905 
1906  new_stonith->cmds->query = stonith_api_query;
1907  new_stonith->cmds->remove_device = stonith_api_remove_device;
1908  new_stonith->cmds->register_device = stonith_api_register_device;
1909 
1910  new_stonith->cmds->remove_level = stonith_api_remove_level;
1911  new_stonith->cmds->remove_level_full = stonith_api_remove_level_full;
1912  new_stonith->cmds->register_level = stonith_api_register_level;
1913  new_stonith->cmds->register_level_full = stonith_api_register_level_full;
1914 
1915  new_stonith->cmds->remove_callback = stonith_api_del_callback;
1916  new_stonith->cmds->register_callback = stonith_api_add_callback;
1917  new_stonith->cmds->remove_notification = stonith_api_del_notification;
1918  new_stonith->cmds->register_notification = stonith_api_add_notification;
1919 
1920  new_stonith->cmds->validate = stonith_api_validate;
1921 /* *INDENT-ON* */
1922 
1923  return new_stonith;
1924 }
1925 
1935 int
1936 stonith_api_connect_retry(stonith_t *st, const char *name, int max_attempts)
1937 {
1938  int rc = -EINVAL; // if max_attempts is not positive
1939 
1940  for (int attempt = 1; attempt <= max_attempts; attempt++) {
1941  rc = st->cmds->connect(st, name, NULL);
1942  if (rc == pcmk_ok) {
1943  return pcmk_ok;
1944  } else if (attempt < max_attempts) {
1945  crm_notice("Fencer connection attempt %d of %d failed (retrying in 2s): %s "
1946  QB_XS " rc=%d",
1947  attempt, max_attempts, pcmk_strerror(rc), rc);
1948  sleep(2);
1949  }
1950  }
1951  crm_notice("Could not connect to fencer: %s " QB_XS " rc=%d",
1952  pcmk_strerror(rc), rc);
1953  return rc;
1954 }
1955 
1957 stonith_key_value_add(stonith_key_value_t * head, const char *key, const char *value)
1958 {
1959  stonith_key_value_t *p, *end;
1960 
1961  p = pcmk__assert_alloc(1, sizeof(stonith_key_value_t));
1962  p->key = pcmk__str_copy(key);
1963  p->value = pcmk__str_copy(value);
1964 
1965  end = head;
1966  while (end && end->next) {
1967  end = end->next;
1968  }
1969 
1970  if (end) {
1971  end->next = p;
1972  } else {
1973  head = p;
1974  }
1975 
1976  return head;
1977 }
1978 
1979 void
1980 stonith_key_value_freeall(stonith_key_value_t * head, int keys, int values)
1981 {
1983 
1984  while (head) {
1985  p = head->next;
1986  if (keys) {
1987  free(head->key);
1988  }
1989  if (values) {
1990  free(head->value);
1991  }
1992  free(head);
1993  head = p;
1994  }
1995 }
1996 
1997 #define api_log_open() openlog("stonith-api", LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON)
1998 #define api_log(level, fmt, args...) syslog(level, "%s: "fmt, __func__, args)
1999 
2000 int
2001 stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off)
2002 {
2003  int rc = pcmk_ok;
2005  const char *action = off? PCMK_ACTION_OFF : PCMK_ACTION_REBOOT;
2006 
2007  api_log_open();
2008  if (st == NULL) {
2009  api_log(LOG_ERR, "API initialization failed, could not kick (%s) node %u/%s",
2010  action, nodeid, uname);
2011  return -EPROTO;
2012  }
2013 
2014  rc = st->cmds->connect(st, "stonith-api", NULL);
2015  if (rc != pcmk_ok) {
2016  api_log(LOG_ERR, "Connection failed, could not kick (%s) node %u/%s : %s (%d)",
2017  action, nodeid, uname, pcmk_strerror(rc), rc);
2018  } else {
2019  char *name = (uname == NULL)? pcmk__itoa(nodeid) : strdup(uname);
2020  int opts = 0;
2021 
2024  if ((uname == NULL) && (nodeid > 0)) {
2026  }
2027  rc = st->cmds->fence(st, opts, name, action, timeout, 0);
2028  free(name);
2029 
2030  if (rc != pcmk_ok) {
2031  api_log(LOG_ERR, "Could not kick (%s) node %u/%s : %s (%d)",
2032  action, nodeid, uname, pcmk_strerror(rc), rc);
2033  } else {
2034  api_log(LOG_NOTICE, "Node %u/%s kicked: %s", nodeid, uname, action);
2035  }
2036  }
2037 
2039  return rc;
2040 }
2041 
2042 time_t
2043 stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress)
2044 {
2045  int rc = pcmk_ok;
2046  time_t when = 0;
2048  stonith_history_t *history = NULL, *hp = NULL;
2049 
2050  if (st == NULL) {
2051  api_log(LOG_ERR, "Could not retrieve fence history for %u/%s: "
2052  "API initialization failed", nodeid, uname);
2053  return when;
2054  }
2055 
2056  rc = st->cmds->connect(st, "stonith-api", NULL);
2057  if (rc != pcmk_ok) {
2058  api_log(LOG_NOTICE, "Connection failed: %s (%d)", pcmk_strerror(rc), rc);
2059  } else {
2060  int entries = 0;
2061  int progress = 0;
2062  int completed = 0;
2063  int opts = 0;
2064  char *name = (uname == NULL)? pcmk__itoa(nodeid) : strdup(uname);
2065 
2067  if ((uname == NULL) && (nodeid > 0)) {
2069  }
2070  rc = st->cmds->history(st, opts, name, &history, 120);
2071  free(name);
2072 
2073  for (hp = history; hp; hp = hp->next) {
2074  entries++;
2075  if (in_progress) {
2076  progress++;
2077  if (hp->state != st_done && hp->state != st_failed) {
2078  when = time(NULL);
2079  }
2080 
2081  } else if (hp->state == st_done) {
2082  completed++;
2083  if (hp->completed > when) {
2084  when = hp->completed;
2085  }
2086  }
2087  }
2088 
2089  stonith_history_free(history);
2090 
2091  if(rc == pcmk_ok) {
2092  api_log(LOG_INFO, "Found %d entries for %u/%s: %d in progress, %d completed", entries, nodeid, uname, progress, completed);
2093  } else {
2094  api_log(LOG_ERR, "Could not retrieve fence history for %u/%s: %s (%d)", nodeid, uname, pcmk_strerror(rc), rc);
2095  }
2096  }
2097 
2099 
2100  if(when) {
2101  api_log(LOG_INFO, "Node %u/%s last kicked at: %ld", nodeid, uname, (long int)when);
2102  }
2103  return when;
2104 }
2105 
2106 bool
2107 stonith_agent_exists(const char *agent, int timeout)
2108 {
2109  stonith_t *st = NULL;
2110  stonith_key_value_t *devices = NULL;
2111  stonith_key_value_t *dIter = NULL;
2112  bool rc = FALSE;
2113 
2114  if (agent == NULL) {
2115  return rc;
2116  }
2117 
2118  st = stonith_api_new();
2119  if (st == NULL) {
2120  crm_err("Could not list fence agents: API memory allocation failed");
2121  return FALSE;
2122  }
2123  st->cmds->list_agents(st, st_opt_sync_call, NULL, &devices, timeout == 0 ? 120 : timeout);
2124 
2125  for (dIter = devices; dIter != NULL; dIter = dIter->next) {
2126  if (pcmk__str_eq(dIter->value, agent, pcmk__str_none)) {
2127  rc = TRUE;
2128  break;
2129  }
2130  }
2131 
2132  stonith_key_value_freeall(devices, 1, 1);
2134  return rc;
2135 }
2136 
2137 const char *
2139 {
2140  if (action == NULL) {
2141  return "fencing";
2142  } else if (strcmp(action, PCMK_ACTION_ON) == 0) {
2143  return "unfencing";
2144  } else if (strcmp(action, PCMK_ACTION_OFF) == 0) {
2145  return "turning off";
2146  } else {
2147  return action;
2148  }
2149 }
2150 
2159 static void
2160 parse_list_line(const char *line, int len, GList **output)
2161 {
2162  size_t i = 0;
2163  size_t entry_start = 0;
2164 
2165  /* Skip complaints about additional parameters device doesn't understand
2166  *
2167  * @TODO Document or eliminate the implied restriction of target names
2168  */
2169  if (strstr(line, "invalid") || strstr(line, "variable")) {
2170  crm_debug("Skipping list output line: %s", line);
2171  return;
2172  }
2173 
2174  // Process line content, character by character
2175  for (i = 0; i <= len; i++) {
2176 
2177  if (isspace(line[i]) || (line[i] == ',') || (line[i] == ';')
2178  || (line[i] == '\0')) {
2179  // We've found a separator (i.e. the end of an entry)
2180 
2181  int rc = 0;
2182  char *entry = NULL;
2183 
2184  if (i == entry_start) {
2185  // Skip leading and sequential separators
2186  entry_start = i + 1;
2187  continue;
2188  }
2189 
2190  entry = pcmk__assert_alloc(i - entry_start + 1, sizeof(char));
2191 
2192  /* Read entry, stopping at first separator
2193  *
2194  * @TODO Document or eliminate these character restrictions
2195  */
2196  rc = sscanf(line + entry_start, "%[a-zA-Z0-9_-.]", entry);
2197  if (rc != 1) {
2198  crm_warn("Could not parse list output entry: %s "
2199  QB_XS " entry_start=%d position=%d",
2200  line + entry_start, entry_start, i);
2201  free(entry);
2202 
2203  } else if (pcmk__strcase_any_of(entry, PCMK_ACTION_ON,
2204  PCMK_ACTION_OFF, NULL)) {
2205  /* Some agents print the target status in the list output,
2206  * though none are known now (the separate list-status command
2207  * is used for this, but it can also print "UNKNOWN"). To handle
2208  * this possibility, skip such entries.
2209  *
2210  * @TODO Document or eliminate the implied restriction of target
2211  * names.
2212  */
2213  free(entry);
2214 
2215  } else {
2216  // We have a valid entry
2217  *output = g_list_append(*output, entry);
2218  }
2219  entry_start = i + 1;
2220  }
2221  }
2222 }
2223 
2245 GList *
2246 stonith__parse_targets(const char *target_spec)
2247 {
2248  GList *targets = NULL;
2249 
2250  if (target_spec != NULL) {
2251  size_t out_len = strlen(target_spec);
2252  size_t line_start = 0; // Starting index of line being processed
2253 
2254  for (size_t i = 0; i <= out_len; ++i) {
2255  if ((target_spec[i] == '\n') || (target_spec[i] == '\0')
2256  || ((target_spec[i] == '\\') && (target_spec[i + 1] == 'n'))) {
2257  // We've reached the end of one line of output
2258 
2259  int len = i - line_start;
2260 
2261  if (len > 0) {
2262  char *line = strndup(target_spec + line_start, len);
2263 
2264  line[len] = '\0'; // Because it might be a newline
2265  parse_list_line(line, len, &targets);
2266  free(line);
2267  }
2268  if (target_spec[i] == '\\') {
2269  ++i; // backslash-n takes up two positions
2270  }
2271  line_start = i + 1;
2272  }
2273  }
2274  }
2275  return targets;
2276 }
2277 
2289 const char *
2291  const stonith_history_t *top_history)
2292 {
2293  const char *other = NULL;
2294 
2295  for (const stonith_history_t *prev_hp = top_history;
2296  prev_hp != NULL; prev_hp = prev_hp->next) {
2297  if (prev_hp == event) {
2298  break;
2299  }
2300  if ((prev_hp->state == st_done) &&
2301  pcmk__str_eq(event->target, prev_hp->target, pcmk__str_casei) &&
2302  pcmk__str_eq(event->action, prev_hp->action, pcmk__str_none) &&
2303  ((event->completed < prev_hp->completed) ||
2304  ((event->completed == prev_hp->completed) && (event->completed_nsec < prev_hp->completed_nsec)))) {
2305 
2306  if ((event->delegate == NULL)
2307  || pcmk__str_eq(event->delegate, prev_hp->delegate,
2308  pcmk__str_casei)) {
2309  // Prefer equivalent fencing by same executioner
2310  return prev_hp->delegate;
2311 
2312  } else if (other == NULL) {
2313  // Otherwise remember first successful executioner
2314  other = (prev_hp->delegate == NULL)? "some node" : prev_hp->delegate;
2315  }
2316  }
2317  }
2318  return other;
2319 }
2320 
2331 {
2332  stonith_history_t *new = NULL, *pending = NULL, *hp, *np, *tmp;
2333 
2334  for (hp = history; hp; ) {
2335  tmp = hp->next;
2336  if ((hp->state == st_done) || (hp->state == st_failed)) {
2337  /* sort into new */
2338  if ((!new) || (hp->completed > new->completed) ||
2339  ((hp->completed == new->completed) && (hp->completed_nsec > new->completed_nsec))) {
2340  hp->next = new;
2341  new = hp;
2342  } else {
2343  np = new;
2344  do {
2345  if ((!np->next) || (hp->completed > np->next->completed) ||
2346  ((hp->completed == np->next->completed) && (hp->completed_nsec > np->next->completed_nsec))) {
2347  hp->next = np->next;
2348  np->next = hp;
2349  break;
2350  }
2351  np = np->next;
2352  } while (1);
2353  }
2354  } else {
2355  /* put into pending */
2356  hp->next = pending;
2357  pending = hp;
2358  }
2359  hp = tmp;
2360  }
2361 
2362  /* pending actions don't have a completed-stamp so make them go front */
2363  if (pending) {
2364  stonith_history_t *last_pending = pending;
2365 
2366  while (last_pending->next) {
2367  last_pending = last_pending->next;
2368  }
2369 
2370  last_pending->next = new;
2371  new = pending;
2372  }
2373  return new;
2374 }
2375 
2383 const char *
2385 {
2386  switch (state) {
2387  case st_query: return "querying";
2388  case st_exec: return "executing";
2389  case st_done: return "completed";
2390  case st_duplicate: return "duplicate";
2391  case st_failed: return "failed";
2392  }
2393  return "unknown";
2394 }
2395 
2398  bool (*matching_fn)(stonith_history_t *, void *),
2399  void *user_data)
2400 {
2401  for (stonith_history_t *hp = history; hp; hp = hp->next) {
2402  if (matching_fn(hp, user_data)) {
2403  return hp;
2404  }
2405  }
2406 
2407  return NULL;
2408 }
2409 
2410 bool
2412 {
2413  return history->state != st_failed && history->state != st_done;
2414 }
2415 
2416 bool
2417 stonith__event_state_eq(stonith_history_t *history, void *user_data)
2418 {
2419  return history->state == GPOINTER_TO_INT(user_data);
2420 }
2421 
2422 bool
2424 {
2425  return history->state != GPOINTER_TO_INT(user_data);
2426 }
2427 
2428 void
2429 stonith__device_parameter_flags(uint32_t *device_flags, const char *device_name,
2430  xmlNode *metadata)
2431 {
2432  xmlXPathObjectPtr xpath = NULL;
2433  int max = 0;
2434  int lpc = 0;
2435 
2436  CRM_CHECK((device_flags != NULL) && (metadata != NULL), return);
2437 
2438  xpath = xpath_search(metadata, "//" PCMK_XE_PARAMETER);
2439  max = numXpathResults(xpath);
2440 
2441  if (max <= 0) {
2442  freeXpathObject(xpath);
2443  return;
2444  }
2445 
2446  for (lpc = 0; lpc < max; lpc++) {
2447  const char *parameter = NULL;
2448  xmlNode *match = getXpathResult(xpath, lpc);
2449 
2450  CRM_LOG_ASSERT(match != NULL);
2451  if (match == NULL) {
2452  continue;
2453  }
2454 
2455  parameter = crm_element_value(match, PCMK_XA_NAME);
2456 
2457  if (pcmk__str_eq(parameter, "plug", pcmk__str_casei)) {
2458  stonith__set_device_flags(*device_flags, device_name,
2460 
2461  } else if (pcmk__str_eq(parameter, "port", pcmk__str_casei)) {
2462  stonith__set_device_flags(*device_flags, device_name,
2464  }
2465  }
2466 
2467  freeXpathObject(xpath);
2468 }
2469 
2489 int
2490 stonith__metadata_async(const char *agent, int timeout_sec,
2491  void (*callback)(int pid,
2493  void *user_data),
2494  void *user_data)
2495 {
2496  switch (stonith_get_namespace(agent, NULL)) {
2497  case st_namespace_rhcs:
2498  {
2499  stonith_action_t *action = NULL;
2500  int rc = pcmk_ok;
2501 
2503  NULL, 0, timeout_sec, NULL,
2504  NULL, NULL);
2505 
2506  rc = stonith__execute_async(action, user_data, callback, NULL);
2507  if (rc != pcmk_ok) {
2508  callback(0, stonith__action_result(action), user_data);
2510  }
2511  return pcmk_legacy2rc(rc);
2512  }
2513 
2514 #if HAVE_STONITH_STONITH_H
2515  case st_namespace_lha:
2516  // LHA metadata is simply synthesized, so simulate async
2517  {
2520  .execution_status = PCMK_EXEC_DONE,
2521  .exit_reason = NULL,
2522  .action_stdout = NULL,
2523  .action_stderr = NULL,
2524  };
2525 
2526  stonith__lha_metadata(agent, timeout_sec,
2528  callback(0, &result, user_data);
2530  return pcmk_rc_ok;
2531  }
2532 #endif
2533 
2534  default:
2535  {
2538  .execution_status = PCMK_EXEC_ERROR_HARD,
2539  .exit_reason = crm_strdup_printf("No such agent '%s'",
2540  agent),
2541  .action_stdout = NULL,
2542  .action_stderr = NULL,
2543  };
2544 
2545  callback(0, &result, user_data);
2547  return ENOENT;
2548  }
2549  }
2550 }
2551 
2560 int
2562 {
2563  if ((data == NULL) || (data->opaque == NULL)) {
2564  return CRM_EX_ERROR;
2565  }
2566  return ((pcmk__action_result_t *) data->opaque)->exit_status;
2567 }
2568 
2577 int
2579 {
2580  if ((data == NULL) || (data->opaque == NULL)) {
2581  return PCMK_EXEC_UNKNOWN;
2582  }
2583  return ((pcmk__action_result_t *) data->opaque)->execution_status;
2584 }
2585 
2594 const char *
2596 {
2597  if ((data == NULL) || (data->opaque == NULL)) {
2598  return NULL;
2599  }
2600  return ((pcmk__action_result_t *) data->opaque)->exit_reason;
2601 }
2602 
2611 int
2613 {
2614  if ((event == NULL) || (event->opaque == NULL)) {
2615  return CRM_EX_ERROR;
2616  } else {
2617  struct event_private *event_private = event->opaque;
2618 
2619  return event_private->result.exit_status;
2620  }
2621 }
2622 
2631 int
2633 {
2634  if ((event == NULL) || (event->opaque == NULL)) {
2635  return PCMK_EXEC_UNKNOWN;
2636  } else {
2637  struct event_private *event_private = event->opaque;
2638 
2639  return event_private->result.execution_status;
2640  }
2641 }
2642 
2651 const char *
2653 {
2654  if ((event == NULL) || (event->opaque == NULL)) {
2655  return NULL;
2656  } else {
2657  struct event_private *event_private = event->opaque;
2658 
2659  return event_private->result.exit_reason;
2660  }
2661 }
2662 
2673 char *
2675 {
2676  // Use somewhat readable defaults
2677  const char *origin = pcmk__s(event->client_origin, "a client");
2678  const char *origin_node = pcmk__s(event->origin, "a node");
2679  const char *executioner = pcmk__s(event->executioner, "the cluster");
2680  const char *device = pcmk__s(event->device, "unknown");
2681  const char *action = pcmk__s(event->action, event->operation);
2682  const char *target = pcmk__s(event->target, "no node");
2683  const char *reason = stonith__event_exit_reason(event);
2684  const char *status;
2685 
2686  if (action == NULL) {
2687  action = "(unknown)";
2688  }
2689 
2691  status = pcmk_exec_status_str(stonith__event_execution_status(event));
2692  } else if (stonith__event_exit_status(event) != CRM_EX_OK) {
2693  status = pcmk_exec_status_str(PCMK_EXEC_ERROR);
2694  } else {
2695  status = crm_exit_str(CRM_EX_OK);
2696  }
2697 
2698  if (pcmk__str_eq(event->operation, PCMK__VALUE_ST_NOTIFY_HISTORY,
2699  pcmk__str_none)) {
2700  return crm_strdup_printf("Fencing history may have changed");
2701 
2702  } else if (pcmk__str_eq(event->operation, STONITH_OP_DEVICE_ADD,
2703  pcmk__str_none)) {
2704  return crm_strdup_printf("A fencing device (%s) was added", device);
2705 
2706  } else if (pcmk__str_eq(event->operation, STONITH_OP_DEVICE_DEL,
2707  pcmk__str_none)) {
2708  return crm_strdup_printf("A fencing device (%s) was removed", device);
2709 
2710  } else if (pcmk__str_eq(event->operation, STONITH_OP_LEVEL_ADD,
2711  pcmk__str_none)) {
2712  return crm_strdup_printf("A fencing topology level (%s) was added",
2713  device);
2714 
2715  } else if (pcmk__str_eq(event->operation, STONITH_OP_LEVEL_DEL,
2716  pcmk__str_none)) {
2717  return crm_strdup_printf("A fencing topology level (%s) was removed",
2718  device);
2719  }
2720 
2721  // event->operation should be PCMK__VALUE_ST_NOTIFY_FENCE at this point
2722 
2723  return crm_strdup_printf("Operation %s of %s by %s for %s@%s: %s%s%s%s (ref=%s)",
2724  action, target, executioner, origin, origin_node,
2725  status,
2726  ((reason == NULL)? "" : " ("), pcmk__s(reason, ""),
2727  ((reason == NULL)? "" : ")"),
2728  pcmk__s(event->id, "(none)"));
2729 }
void stonith__destroy_action(stonith_action_t *action)
Definition: st_actions.c:216
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:213
#define PCMK__XA_ST_DELEGATE
struct stonith_action_s stonith_action_t
Definition: internal.h:56
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:563
void stonith_history_free(stonith_history_t *history)
Definition: st_client.c:761
#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:2632
struct stonith_history_s * next
Definition: stonith-ng.h:137
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition: xml.c:805
#define PCMK__VALUE_ST_NOTIFY
A dumping ground.
#define PCMK__XA_NAMESPACE
Invoke callback only if request succeeded.
Definition: stonith-ng.h:86
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition: xml_element.c:42
#define crm_notice(fmt, args...)
Definition: logging.h:365
const char * pcmk_strerror(int rc)
Definition: results.c:257
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: xml_element.c:1291
#define PCMK_XA_NAME
Definition: xml_names.h:330
#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:2429
stonith_t * stonith
Definition: st_client.c:79
#define api_log_open()
Definition: st_client.c:1997
int stonith__legacy2status(int rc)
Definition: st_actions.c:401
#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:249
Requested item does not exist.
Definition: results.h:267
int pcmk_rc2legacy(int rc)
Definition: results.c:654
bool stonith__event_state_neq(stonith_history_t *history, void *user_data)
Definition: st_client.c:2423
const char * name
Definition: cib.c:26
enum pcmk_ipc_server type
Definition: cpg.c:51
#define PCMK_ACTION_LIST
Definition: actions.h:43
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1027
stonith_key_value_t * stonith_key_value_add(stonith_key_value_t *head, const char *key, const char *value)
Definition: st_client.c:1957
#define PCMK__XA_ST_OUTPUT
void stonith_dump_pending_callbacks(stonith_t *stonith)
Definition: st_client.c:1368
Interpret target as node cluster layer ID instead of name.
Definition: stonith-ng.h:77
#define stonith__set_device_flags(device_flags, device_id, flags_to_set)
Definition: internal.h:34
bool stonith__event_state_eq(stonith_history_t *history, void *user_data)
Definition: st_client.c:2417
#define PCMK_ACTION_ON
Definition: actions.h:55
int stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off)
Definition: st_client.c:2001
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:423
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:515
xmlNode * stonith_create_op(int call_id, const char *token, const char *op, xmlNode *data, int call_options)
Definition: st_client.c:808
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:166
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:449
#define STONITH_OP_FENCE
Definition: internal.h:119
const char * stonith_action_str(const char *action)
Turn fence action into a more readable string.
Definition: st_client.c:2138
struct stonith_key_value_s * next
Definition: stonith-ng.h:126
#define PCMK_ACTION_MONITOR
Definition: actions.h:51
#define PCMK_XA_TARGET_PATTERN
Definition: xml_names.h:421
#define PCMK_XA_EXIT_REASON
Definition: xml_names.h:274
int stonith__result2rc(const pcmk__action_result_t *result)
Definition: st_actions.c:327
enum pcmk_exec_status execution_status
struct mainloop_io_s mainloop_io_t
Definition: mainloop.h:41
#define PCMK__XE_ATTRIBUTES
#define PCMK__XE_STONITH_COMMAND
Unspecified error.
Definition: results.h:232
const char * stonith__exit_reason(const stonith_callback_data_t *data)
Definition: st_client.c:2595
void stonith_key_value_freeall(stonith_key_value_t *head, int keys, int values)
Definition: st_client.c:1980
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:418
#define PCMK_XA_INDEX
Definition: xml_names.h:305
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:796
#define PCMK__VALUE_ST_NOTIFY_DISCONNECT
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:196
stonith_namespace
Definition: stonith-ng.h:106
#define PCMK__XA_SUBT
#define PCMK__XA_ST_NOTIFY_ACTIVATE
long crm_ipc_read(crm_ipc_t *client)
Definition: ipc_client.c:1118
#define PCMK__XA_RSC_PROVIDES
int call_id
Definition: internal.h:119
#define PCMK_XA_TARGET_ATTRIBUTE
Definition: xml_names.h:419
Action did not complete in time.
Definition: results.h:311
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:609
The fencing target is allowed to execute the request.
Definition: stonith-ng.h:53
Execution failed, do not retry on node.
Definition: results.h:314
Do not return any reply from server.
Definition: stonith-ng.h:65
#define LOG_NEVER
Definition: logging.h:48
#define STONITH_OP_NOTIFY
Definition: internal.h:126
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:125
#define STONITH_OP_DEVICE_ADD
Definition: internal.h:121
int(* confirm)(stonith_t *stonith, int call_options, const char *target)
Manually confirm that a node has been fenced.
Definition: stonith-ng.h:393
#define PCMK__XE_ST_CALLDATA
#define STONITH_OP_EXEC
Definition: internal.h:116
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition: xml_element.c:407
#define CRM_OP_REGISTER
Definition: crm.h:122
const char * action
Definition: pcmk_fence.c:32
const char * crm_ipc_buffer(crm_ipc_t *client)
Definition: ipc_client.c:1166
#define PCMK_XA_DEVICES
Definition: xml_names.h:264
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:300
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
void pcmk__xml_free(xmlNode *xml)
Definition: xml.c:789
#define PCMK_XA_AGENT
Definition: xml_names.h:234
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: xml_element.c:1015
int(* remove_callback)(stonith_t *stonith, int call_id, bool all_callbacks)
Unregister callbacks for asynchronous fencing results.
Definition: stonith-ng.h:465
int pcmk__connect_generic_ipc(crm_ipc_t *ipc)
Definition: ipc_client.c:890
#define PCMK_ACTION_STATUS
Definition: actions.h:64
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:540
gboolean stonith__watchdog_fencing_enabled_for_node(const char *node)
Definition: st_client.c:230
time_t stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress)
Definition: st_client.c:2043
int(* free)(stonith_t *st)
Destroy a fencer connection.
Definition: stonith-ng.h:178
#define PCMK__XA_ST_ORIGIN
#define PCMK_DEFAULT_ACTION_TIMEOUT_MS
Default timeout (in milliseconds) for non-metadata actions.
Definition: actions.h:33
#define PCMK__XA_ST_DELAY
int timeout
Definition: internal.h:120
#define PCMK__XA_ST_DATE_NSEC
#define PCMK__UNKNOWN_RESULT
#define PCMK_ACTION_REBOOT
Definition: actions.h:59
#define crm_warn(fmt, args...)
Definition: logging.h:362
const char * stonith_op_state_str(enum op_state state)
Return string equivalent of an operation state value.
Definition: st_client.c:2384
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:1936
const char * crm_exit_str(crm_exit_t exit_code)
Definition: results.c:748
const char * stonith__later_succeeded(const stonith_history_t *event, const stonith_history_t *top_history)
Definition: st_client.c:2290
stonith_t * st
Definition: pcmk_fence.c:30
bool stonith_dispatch(stonith_t *st)
Definition: st_client.c:1665
uint32_t pid
Definition: cpg.c:49
#define crm_debug(fmt, args...)
Definition: logging.h:370
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:2397
#define STONITH_OP_LEVEL_ADD
Definition: internal.h:124
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:345
struct crm_ipc_s crm_ipc_t
Definition: ipc.h:151
enum stonith_state state
Definition: stonith-ng.h:570
unsigned int tolerance
Definition: pcmk_fence.c:35
Used only to initialize variables.
Definition: results.h:307
pcmk__action_result_t * stonith__action_result(stonith_action_t *action)
Definition: st_actions.c:241
#define STONITH_OP_QUERY
Definition: internal.h:118
op_state
Definition: stonith-ng.h:96
GList * stonith__parse_targets(const char *target_spec)
Definition: st_client.c:2246
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition: xml_element.c:1466
#define PCMK_XE_PARAMETER
Definition: xml_names.h:158
#define PCMK__VALUE_ST_NOTIFY_HISTORY
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: xml_element.c:1168
guint pcmk__create_timer(guint interval_ms, GSourceFunc fn, gpointer data)
Definition: utils.c:401
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:121
int stonith__execution_status(const stonith_callback_data_t *data)
Definition: st_client.c:2578
#define crm_trace(fmt, args...)
Definition: logging.h:372
#define stonith__set_call_options(st_call_opts, call_for, flags_to_set)
Definition: internal.h:41
#define crm_log_xml_debug(xml, text)
Definition: logging.h:379
bool stonith_agent_exists(const char *agent, int timeout)
Definition: st_client.c:2107
#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:259
#define crm_log_xml_warn(xml, text)
Definition: logging.h:376
Action completed, result is known.
Definition: results.h:309
void stonith__xe_get_result(const xmlNode *xml, pcmk__action_result_t *result)
Definition: st_actions.c:491
int(* disconnect)(stonith_t *st)
Disconnect from the local stonith daemon.
Definition: stonith-ng.h:199
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
#define STONITH_OP_DEVICE_DEL
Definition: internal.h:122
#define ECOMM
Definition: portability.h:41
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:941
#define PCMK_XA_ID
Definition: xml_names.h:301
Success.
Definition: results.h:231
void crm_ipc_destroy(crm_ipc_t *client)
Definition: ipc_client.c:966
int pcmk_legacy2rc(int legacy_rc)
Definition: results.c:667
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
xmlNode * create_device_registration_xml(const char *id, enum stonith_namespace standard, const char *agent, const stonith_key_value_t *params, const char *rsc_provides)
Definition: st_client.c:292
const char * stonith__event_exit_reason(const stonith_event_t *event)
Definition: st_client.c:2652
void stonith_api_delete(stonith_t *stonith)
Definition: st_client.c:1725
int(* connect)(stonith_t *st, const char *name, int *stonith_fd)
Connect to the local fencer.
Definition: stonith-ng.h:190
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:279
char * stonith__event_description(const stonith_event_t *event)
Definition: st_client.c:2674
#define api_log(level, fmt, args...)
Definition: st_client.c:1998
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1051
int stonith__validate(stonith_t *st, int call_options, const char *rsc_id, const char *namespace_s, const char *agent, GHashTable *params, int timeout_sec, char **output, char **error_output)
Definition: st_client.c:1740
#define pcmk__str_copy(str)
#define PCMK__VALUE_ST_ASYNC_TIMEOUT_VALUE
xmlNode * pcmk__xml_parse(const char *input)
Definition: xml_io.c:168
uint32_t id
Definition: cpg.c:48
#define STONITH_OP_FENCE_HISTORY
Definition: internal.h:123
stonith_history_t * stonith__sort_history(stonith_history_t *history)
Definition: st_client.c:2330
int(* remove_device)(stonith_t *st, int options, const char *name)
Unregister a fence device with the local fencer.
Definition: stonith-ng.h:211
struct stonith_private_s stonith_private_t
Wait for request to be completed before returning.
Definition: stonith-ng.h:80
xmlNode * pcmk__xe_next(const xmlNode *node, const char *element_name)
Definition: xml_element.c:106
bool crm_ipc_connected(crm_ipc_t *client)
Definition: ipc_client.c:1028
#define pcmk__assert(expr)
const char * target
Definition: pcmk_fence.c:31
#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:406
gboolean stonith__watchdog_fencing_enabled_for_node_api(stonith_t *st, const char *node)
Definition: st_client.c:171
int crm_ipc_ready(crm_ipc_t *client)
Check whether an IPC connection is ready to be read.
Definition: ipc_client.c:1060
char * client_origin
Definition: stonith-ng.h:156
#define PCMK_STONITH_HOST_ARGUMENT
Definition: agents.h:40
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:375
struct stonith_callback_client_s stonith_callback_client_t
#define PCMK_XE_FENCING_LEVEL
Definition: xml_names.h:117
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:685
pcmk__action_result_t result
Definition: pcmk_fence.c:37
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:299
#define pcmk__set_ipc_flags(ipc_flags, ipc_name, flags_to_set)
Definition: ipc_internal.h:198
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:947
#define crm_err(fmt, args...)
Definition: logging.h:359
#define G_PRIORITY_MEDIUM
Definition: mainloop.h:194
#define PCMK__XE_ST_HISTORY
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:2490
#define ENOTUNIQ
Definition: portability.h:36
int stonith__event_exit_status(const stonith_event_t *event)
Definition: st_client.c:2612
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:488
stonith_api_operations_t * cmds
Definition: stonith-ng.h:573
stonith_t * stonith_api_new(void)
Definition: st_client.c:1858
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:244
int delay
Definition: pcmk_fence.c:36
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:229
int pcmk__ipc_fd(crm_ipc_t *ipc, int *fd)
Definition: ipc_client.c:1001
#define crm_log_xml_notice(xml, text)
Definition: logging.h:377
Request that server send an update with optimal callback timeout.
Definition: stonith-ng.h:83
Fencing aka. STONITH.
xmlNode * getXpathResult(xmlXPathObjectPtr xpathObj, int index)
Definition: xpath.c:58
char * executioner
Definition: stonith-ng.h:151
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: xml_element.c:1201
#define PCMK_ACTION_METADATA
Definition: actions.h:48
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:844
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:264
#define PCMK__XA_ST_DATE
char * operation
Definition: stonith-ng.h:146
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:330
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:362
#define pcmk_ok
Definition: results.h:65
#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:2411
#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:316
void * st_private
Definition: stonith-ng.h:572
#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:1074
#define crm_log_xml_trace(xml, text)
Definition: logging.h:380
#define PCMK_ACTION_OFF
Definition: actions.h:54
#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:916
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:380
int(* remove_notification)(stonith_t *stonith, const char *event)
Unregister callbacks for fence notifications.
Definition: stonith-ng.h:430
#define PCMK__XA_ST_STATE
#define pcmk__assert_alloc(nmemb, size)
Definition: internal.h:257
#define STONITH_WATCHDOG_ID
Definition: internal.h:133
void pcmk__reset_result(pcmk__action_result_t *result)
Definition: results.c:1163
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:1260
crm_ipc_flags
Definition: ipc.h:135
#define PCMK__XA_ST_CLIENTID
void crm_ipc_close(crm_ipc_t *client)
Definition: ipc_client.c:953
CRM_TRACE_INIT_DATA(stonith)
int stonith__exit_status(const stonith_callback_data_t *data)
Definition: st_client.c:2561
#define PCMK_XA_TARGET
Definition: xml_names.h:418
unsigned int timeout
Definition: pcmk_fence.c:34
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:668
Execution failed, may be retried.
Definition: results.h:313
#define crm_info(fmt, args...)
Definition: logging.h:367
int call_id
Definition: stonith-ng.h:571
void pcmk__insert_dup(GHashTable *table, const char *name, const char *value)
Definition: strings.c:703
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:416
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Dispatch function for an IPC connection used as mainloop source.
Definition: mainloop.h:96
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
gboolean pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
Definition: strings.c:982
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
Definition: xml_element.c:1070