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