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