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