pacemaker  1.1.24-3850484742
Scalable High-Availability cluster resource manager
services.c
Go to the documentation of this file.
1 /*
2  * Copyright 2010-2019 Andrew Beekhof <andrew@beekhof.net>
3  *
4  * This source code is licensed under the GNU Lesser General Public License
5  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
6  */
7 
8 #include <crm_internal.h>
9 
10 #ifndef _GNU_SOURCE
11 # define _GNU_SOURCE
12 #endif
13 
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <stdio.h>
17 
18 #include <errno.h>
19 #include <unistd.h>
20 #include <dirent.h>
21 #include <fcntl.h>
22 
23 #include <crm/crm.h>
24 #include <crm/common/mainloop.h>
25 #include <crm/services.h>
26 #include <crm/msg_xml.h>
27 #include "services_private.h"
28 
29 #if SUPPORT_UPSTART
30 # include <upstart.h>
31 #endif
32 
33 #if SUPPORT_SYSTEMD
34 # include <systemd.h>
35 #endif
36 
37 /* TODO: Develop a rollover strategy */
38 
39 static int operations = 0;
40 static GHashTable *recurring_actions = NULL;
41 
42 /* ops waiting to run async because of conflicting active
43  * pending ops */
44 static GList *blocked_ops = NULL;
45 
46 /* ops currently active (in-flight) */
47 static GList *inflight_ops = NULL;
48 
49 static void handle_blocked_ops(void);
50 
52 services_action_create(const char *name, const char *action, int interval, int timeout)
53 {
54  return resources_action_create(name, PCMK_RESOURCE_CLASS_LSB, NULL, name,
55  action, interval, timeout, NULL, 0);
56 }
57 
58 static char *
59 services__lsb_agent_path(const char *agent)
60 {
61  return (*agent == '/')? strdup(agent)
62  : crm_strdup_printf("%s/%s", LSB_ROOT_DIR, agent);
63 }
64 
65 static bool
66 services__lsb_agent_exists(const char *agent)
67 {
68  bool rc = FALSE;
69  struct stat st;
70  char *path = services__lsb_agent_path(agent);
71 
72  rc = (stat(path, &st) == 0);
73  free(path);
74  return rc;
75 }
76 
88 const char *
89 resources_find_service_class(const char *agent)
90 {
91  /* Priority is:
92  * - lsb
93  * - systemd
94  * - upstart
95  */
96  if (services__lsb_agent_exists(agent)) {
98  }
99 
100 #if SUPPORT_SYSTEMD
101  if (systemd_unit_exists(agent)) {
103  }
104 #endif
105 
106 #if SUPPORT_UPSTART
107  if (upstart_job_exists(agent)) {
109  }
110 #endif
111  return NULL;
112 }
113 
114 static inline void
115 init_recurring_actions(void)
116 {
117  if (recurring_actions == NULL) {
118  recurring_actions = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
119  NULL);
120  }
121 }
122 
131 static inline gboolean
132 inflight_systemd_or_upstart(svc_action_t *op)
133 {
136  && (g_list_find(inflight_ops, op) != NULL);
137 }
138 
151 static char *
152 expand_resource_class(const char *rsc, const char *standard, const char *agent)
153 {
154  char *expanded_class = NULL;
155 
156  if (strcasecmp(standard, PCMK_RESOURCE_CLASS_SERVICE) == 0) {
157  const char *found_class = resources_find_service_class(agent);
158 
159  if (found_class) {
160  crm_debug("Found %s agent %s for %s", found_class, agent, rsc);
161  expanded_class = strdup(found_class);
162  } else {
163  crm_info("Assuming resource class lsb for agent %s for %s",
164  agent, rsc);
165  expanded_class = strdup(PCMK_RESOURCE_CLASS_LSB);
166  }
167  } else {
168  expanded_class = strdup(standard);
169  }
170  CRM_ASSERT(expanded_class);
171  return expanded_class;
172 }
173 
174 svc_action_t *
175 resources_action_create(const char *name, const char *standard, const char *provider,
176  const char *agent, const char *action, int interval, int timeout,
177  GHashTable * params, enum svc_action_flags flags)
178 {
179  svc_action_t *op = NULL;
180  uint32_t ra_caps = 0;
181 
182  /*
183  * Do some up front sanity checks before we go off and
184  * build the svc_action_t instance.
185  */
186 
187  if (crm_strlen_zero(name)) {
188  crm_err("Cannot create operation without resource name");
189  goto return_error;
190  }
191 
192  if (crm_strlen_zero(standard)) {
193  crm_err("Cannot create operation for %s without resource class", name);
194  goto return_error;
195  }
196  ra_caps = pcmk_get_ra_caps(standard);
197 
198  if (is_set(ra_caps, pcmk_ra_cap_provider) && crm_strlen_zero(provider)) {
199  crm_err("Cannot create operation for %s without provider", name);
200  goto return_error;
201  }
202 
203  if (crm_strlen_zero(agent)) {
204  crm_err("Cannot create operation for %s without agent name", name);
205  goto return_error;
206  }
207 
208  if (crm_strlen_zero(action)) {
209  crm_err("Cannot create operation for %s without operation name", name);
210  goto return_error;
211  }
212 
213  /*
214  * Sanity checks passed, proceed!
215  */
216 
217  op = calloc(1, sizeof(svc_action_t));
218  op->opaque = calloc(1, sizeof(svc_action_private_t));
219  op->rsc = strdup(name);
220  op->interval = interval;
221  op->timeout = timeout;
222  op->standard = expand_resource_class(name, standard, agent);
223  op->agent = strdup(agent);
224  op->sequence = ++operations;
225  op->flags = flags;
226  op->id = generate_op_key(name, action, interval);
227 
228  if (is_set(ra_caps, pcmk_ra_cap_status) && safe_str_eq(action, "monitor")) {
229  op->action = strdup("status");
230  } else {
231  op->action = strdup(action);
232  }
233 
234  if (is_set(ra_caps, pcmk_ra_cap_provider)) {
235  op->provider = strdup(provider);
236  }
237 
238  if (is_set(ra_caps, pcmk_ra_cap_params)) {
239  op->params = params;
240  params = NULL; // so we don't free them in this function
241  }
242 
243  if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_OCF) == 0) {
244  if (asprintf(&op->opaque->exec, "%s/resource.d/%s/%s", OCF_ROOT_DIR, provider, agent) == -1) {
245  crm_err("Internal error: cannot create agent path");
246  goto return_error;
247  }
248  op->opaque->args[0] = strdup(op->opaque->exec);
249  op->opaque->args[1] = strdup(op->action);
250 
251  } else if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_LSB) == 0) {
252  op->opaque->exec = services__lsb_agent_path(op->agent);
253  op->opaque->args[0] = strdup(op->opaque->exec);
254  op->opaque->args[1] = strdup(op->action);
255 
256 #if SUPPORT_HEARTBEAT
257  } else if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_HB) == 0) {
258  int index;
259  int param_num;
260  char buf_tmp[20];
261  void *value_tmp;
262 
263  if (op->agent[0] == '/') {
264  /* if given an absolute path, use that instead
265  * of tacking on the HB_RA_DIR path to the front */
266  op->opaque->exec = strdup(op->agent);
267  } else if (asprintf(&op->opaque->exec, "%s/%s", HB_RA_DIR, op->agent) == -1) {
268  crm_err("Internal error: cannot create agent path");
269  goto return_error;
270  }
271  op->opaque->args[0] = strdup(op->opaque->exec);
272 
273  /* The "heartbeat" agent class only has positional arguments,
274  * which we keyed by their decimal position number. */
275  param_num = 1;
276  if (op->params) {
277  for (index = 1; index <= MAX_ARGC - 3; index++ ) {
278  snprintf(buf_tmp, sizeof(buf_tmp), "%d", index);
279  value_tmp = g_hash_table_lookup(op->params, buf_tmp);
280  if (value_tmp == NULL) {
281  /* maybe: strdup("") ??
282  * But the old lrmd did simply continue as well. */
283  continue;
284  }
285  op->opaque->args[param_num++] = strdup(value_tmp);
286  }
287 
288  // Heartbeat actions don't need to keep the parameters
289  g_hash_table_destroy(op->params);
290  op->params = NULL;
291  }
292 
293  /* Add operation code as the last argument, */
294  /* and the terminating NULL pointer */
295  op->opaque->args[param_num++] = strdup(op->action);
296  op->opaque->args[param_num] = NULL;
297 #endif
298 #if SUPPORT_SYSTEMD
299  } else if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_SYSTEMD) == 0) {
300  op->opaque->exec = strdup("systemd-dbus");
301 #endif
302 #if SUPPORT_UPSTART
303  } else if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_UPSTART) == 0) {
304  op->opaque->exec = strdup("upstart-dbus");
305 #endif
306 #if SUPPORT_NAGIOS
307  } else if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_NAGIOS) == 0) {
308  if (op->agent[0] == '/') {
309  /* if given an absolute path, use that instead
310  * of tacking on the NAGIOS_PLUGIN_DIR path to the front */
311  op->opaque->exec = strdup(op->agent);
312 
313  } else if (asprintf(&op->opaque->exec, "%s/%s", NAGIOS_PLUGIN_DIR, op->agent) == -1) {
314  crm_err("Internal error: cannot create agent path");
315  goto return_error;
316  }
317 
318  op->opaque->args[0] = strdup(op->opaque->exec);
319 
320  if (safe_str_eq(op->action, "monitor") && op->interval == 0) {
321  /* Invoke --version for a nagios probe */
322  op->opaque->args[1] = strdup("--version");
323 
324  } else if (op->params) {
325  GHashTableIter iter;
326  char *key = NULL;
327  char *value = NULL;
328  int index = 1;
329  static int args_size = sizeof(op->opaque->args) / sizeof(char *);
330 
331  g_hash_table_iter_init(&iter, op->params);
332 
333  while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value) &&
334  index <= args_size - 3) {
335  int len = 3;
336  char *long_opt = NULL;
337 
338  if (safe_str_eq(key, XML_ATTR_CRM_VERSION) || strstr(key, CRM_META "_")) {
339  continue;
340  }
341 
342  len += strlen(key);
343  long_opt = calloc(1, len);
344  sprintf(long_opt, "--%s", key);
345  long_opt[len - 1] = 0;
346 
347  op->opaque->args[index] = long_opt;
348  op->opaque->args[index + 1] = strdup(value);
349  index += 2;
350  }
351  }
352 
353  // Nagios actions don't need to keep the parameters
354  if (op->params != NULL) {
355  g_hash_table_destroy(op->params);
356  op->params = NULL;
357  }
358 #endif
359  } else {
360  crm_err("Unknown resource standard: %s", op->standard);
361  goto return_error;
362  }
363 
364  if(params) {
365  g_hash_table_destroy(params);
366  }
367  return op;
368 
369  return_error:
370  if(params) {
371  g_hash_table_destroy(params);
372  }
374 
375  return NULL;
376 }
377 
378 svc_action_t *
379 services_action_create_generic(const char *exec, const char *args[])
380 {
381  svc_action_t *op;
382  unsigned int cur_arg;
383 
384  op = calloc(1, sizeof(*op));
385  op->opaque = calloc(1, sizeof(svc_action_private_t));
386 
387  op->opaque->exec = strdup(exec);
388  op->opaque->args[0] = strdup(exec);
389 
390  for (cur_arg = 1; args && args[cur_arg - 1]; cur_arg++) {
391  op->opaque->args[cur_arg] = strdup(args[cur_arg - 1]);
392 
393  if (cur_arg == DIMOF(op->opaque->args) - 1) {
394  crm_err("svc_action_t args list not long enough for '%s' execution request.", exec);
395  break;
396  }
397  }
398 
399  return op;
400 }
401 
416 svc_action_t *
417 services_alert_create(const char *id, const char *exec, int timeout,
418  GHashTable *params, int sequence, void *cb_data)
419 {
420  svc_action_t *action = services_action_create_generic(exec, NULL);
421 
422  CRM_ASSERT(action);
423  action->timeout = timeout;
424  action->id = strdup(id);
425  action->params = params;
426  action->sequence = sequence;
427  action->cb_data = cb_data;
428  return action;
429 }
430 
446 int
447 services_action_user(svc_action_t *op, const char *user)
448 {
449  CRM_CHECK((op != NULL) && (user != NULL), return -EINVAL);
450  return crm_user_lookup(user, &(op->opaque->uid), &(op->opaque->gid));
451 }
452 
464 gboolean
466 {
467  action->synchronous = false;
468  action->opaque->callback = cb;
469  return services_os_action_execute(action);
470 }
471 
472 #if SUPPORT_DBUS
473 
480 void
481 services_set_op_pending(svc_action_t *op, DBusPendingCall *pending)
482 {
483  if (op->opaque->pending && (op->opaque->pending != pending)) {
484  if (pending) {
485  crm_info("Lost pending %s DBus call (%p)", op->id, op->opaque->pending);
486  } else {
487  crm_trace("Done with pending %s DBus call (%p)", op->id, op->opaque->pending);
488  }
489  dbus_pending_call_unref(op->opaque->pending);
490  }
491  op->opaque->pending = pending;
492  if (pending) {
493  crm_trace("Updated pending %s DBus call (%p)", op->id, pending);
494  } else {
495  crm_trace("Cleared pending %s DBus call", op->id);
496  }
497 }
498 #endif
499 
500 void
502 {
503  if ((op == NULL) || (op->opaque == NULL)) {
504  return;
505  }
506 
507 #if SUPPORT_DBUS
508  if(op->opaque->timerid != 0) {
509  crm_trace("Removing timer for call %s to %s", op->action, op->rsc);
510  g_source_remove(op->opaque->timerid);
511  op->opaque->timerid = 0;
512  }
513 
514  if(op->opaque->pending) {
515  if (dbus_pending_call_get_completed(op->opaque->pending)) {
516  // This should never be the case
517  crm_warn("Result of %s op %s was unhandled",
518  op->standard, op->id);
519  } else {
520  crm_debug("Will ignore any result of canceled %s op %s",
521  op->standard, op->id);
522  }
523  dbus_pending_call_cancel(op->opaque->pending);
524  services_set_op_pending(op, NULL);
525  }
526 #endif
527 
528  if (op->opaque->stderr_gsource) {
530  op->opaque->stderr_gsource = NULL;
531  }
532 
533  if (op->opaque->stdout_gsource) {
535  op->opaque->stdout_gsource = NULL;
536  }
537 }
538 
539 void
541 {
542  unsigned int i;
543 
544  if (op == NULL) {
545  return;
546  }
547 
548  /* The operation should be removed from all tracking lists by this point.
549  * If it's not, we have a bug somewhere, so bail. That may lead to a
550  * memory leak, but it's better than a use-after-free segmentation fault.
551  */
552  CRM_CHECK(g_list_find(inflight_ops, op) == NULL, return);
553  CRM_CHECK(g_list_find(blocked_ops, op) == NULL, return);
554  CRM_CHECK((recurring_actions == NULL)
555  || (g_hash_table_lookup(recurring_actions, op->id) == NULL),
556  return);
557 
559 
560  if (op->opaque->repeat_timer) {
561  g_source_remove(op->opaque->repeat_timer);
562  op->opaque->repeat_timer = 0;
563  }
564 
565  free(op->id);
566  free(op->opaque->exec);
567 
568  for (i = 0; i < DIMOF(op->opaque->args); i++) {
569  free(op->opaque->args[i]);
570  }
571 
572  free(op->opaque);
573  free(op->rsc);
574  free(op->action);
575 
576  free(op->standard);
577  free(op->agent);
578  free(op->provider);
579 
580  free(op->stdout_data);
581  free(op->stderr_data);
582 
583  if (op->params) {
584  g_hash_table_destroy(op->params);
585  op->params = NULL;
586  }
587 
588  free(op);
589 }
590 
591 gboolean
593 {
594  crm_info("Cancelling %s operation %s", op->standard, op->id);
595 
596  if (recurring_actions) {
597  g_hash_table_remove(recurring_actions, op->id);
598  }
599 
600  if (op->opaque->repeat_timer) {
601  g_source_remove(op->opaque->repeat_timer);
602  op->opaque->repeat_timer = 0;
603  }
604 
605  return TRUE;
606 }
607 
617 gboolean
618 services_action_cancel(const char *name, const char *action, int interval)
619 {
620  gboolean cancelled = FALSE;
621  char *id = generate_op_key(name, action, interval);
622  svc_action_t *op = NULL;
623 
624  /* We can only cancel a recurring action */
625  init_recurring_actions();
626  op = g_hash_table_lookup(recurring_actions, id);
627  if (op == NULL) {
628  goto done;
629  }
630 
631  /* Tell operation_finalize() not to reschedule the operation */
632  op->cancel = TRUE;
633 
634  /* Stop tracking it as a recurring operation, and stop its repeat timer */
636 
637  /* If the op has a PID, it's an in-flight child process, so kill it.
638  *
639  * Whether the kill succeeds or fails, the main loop will send the op to
640  * operation_finished() (and thus operation_finalize()) when the process
641  * goes away.
642  */
643  if (op->pid != 0) {
644  crm_info("Terminating in-flight op %s (pid %d) early because it was cancelled",
645  id, op->pid);
646  cancelled = mainloop_child_kill(op->pid);
647  if (cancelled == FALSE) {
648  crm_err("Termination of %s (pid %d) failed", id, op->pid);
649  }
650  goto done;
651  }
652 
653 #if SUPPORT_DBUS
654  // In-flight systemd and upstart ops don't have a pid
655  if (inflight_systemd_or_upstart(op)) {
656  inflight_ops = g_list_remove(inflight_ops, op);
657 
658  /* This will cause any result that comes in later to be discarded, so we
659  * don't call the callback and free the operation twice.
660  */
662  }
663 #endif
664 
665  // The rest of this is essentially equivalent to operation_finalize(),
666  // except without calling handle_blocked_ops()
667 
668  // Report operation as cancelled
670  if (op->opaque->callback) {
671  op->opaque->callback(op);
672  }
673 
674  blocked_ops = g_list_remove(blocked_ops, op);
676  cancelled = TRUE;
677  // @TODO Initiate handle_blocked_ops() asynchronously
678 
679 done:
680  free(id);
681  return cancelled;
682 }
683 
684 gboolean
685 services_action_kick(const char *name, const char *action, int interval /* ms */)
686 {
687  svc_action_t * op = NULL;
688  char *id = generate_op_key(name, action, interval);
689 
690  init_recurring_actions();
691  op = g_hash_table_lookup(recurring_actions, id);
692  free(id);
693 
694  if (op == NULL) {
695  return FALSE;
696  }
697 
698 
699  if (op->pid || inflight_systemd_or_upstart(op)) {
700  return TRUE;
701  } else {
702  if (op->opaque->repeat_timer) {
703  g_source_remove(op->opaque->repeat_timer);
704  op->opaque->repeat_timer = 0;
705  }
707  return TRUE;
708  }
709 
710 }
711 
720 static gboolean
721 handle_duplicate_recurring(svc_action_t * op)
722 {
723  svc_action_t * dup = NULL;
724 
725  /* check for duplicates */
726  dup = g_hash_table_lookup(recurring_actions, op->id);
727 
728  if (dup && (dup != op)) {
729  /* update user data */
730  if (op->opaque->callback) {
731  dup->opaque->callback = op->opaque->callback;
732  dup->cb_data = op->cb_data;
733  op->cb_data = NULL;
734  }
735  /* immediately execute the next interval */
736  if (dup->pid != 0) {
737  if (op->opaque->repeat_timer) {
738  g_source_remove(op->opaque->repeat_timer);
739  op->opaque->repeat_timer = 0;
740  }
742  }
743  /* free the duplicate */
745  return TRUE;
746  }
747 
748  return FALSE;
749 }
750 
751 inline static gboolean
752 action_exec_helper(svc_action_t * op)
753 {
754  /* Whether a/synchronous must be decided (op->synchronous) beforehand. */
755  if (op->standard
756  && (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_UPSTART) == 0)) {
757 #if SUPPORT_UPSTART
758  return upstart_job_exec(op);
759 #endif
760  } else if (op->standard && strcasecmp(op->standard,
762 #if SUPPORT_SYSTEMD
763  return systemd_unit_exec(op);
764 #endif
765  } else {
766  return services_os_action_execute(op);
767  }
768  /* The 'op' has probably been freed if the execution functions return TRUE
769  for the asynchronous 'op'. */
770  /* Avoid using the 'op' in here. */
771 
772  return FALSE;
773 }
774 
775 void
777 {
778  if (op == NULL) {
779  return;
780  }
781 
782  CRM_ASSERT(op->synchronous == FALSE);
783 
784  /* keep track of ops that are in-flight to avoid collisions in the same namespace */
785  if (op->rsc) {
786  inflight_ops = g_list_append(inflight_ops, op);
787  }
788 }
789 
796 void
798 {
799  /* Op is no longer in-flight or blocked */
800  inflight_ops = g_list_remove(inflight_ops, op);
801  blocked_ops = g_list_remove(blocked_ops, op);
802 
803  /* Op is no longer blocking other ops, so check if any need to run */
804  handle_blocked_ops();
805 }
806 
807 gboolean
809  void (*action_callback) (svc_action_t *),
810  void (*action_fork_callback) (svc_action_t *))
811 {
812  op->synchronous = false;
813  if (action_callback) {
814  op->opaque->callback = action_callback;
815  }
816  if (action_fork_callback) {
817  op->opaque->fork_callback = action_fork_callback;
818  }
819 
820  if (op->interval > 0) {
821  init_recurring_actions();
822  if (handle_duplicate_recurring(op) == TRUE) {
823  /* entry rescheduled, dup freed */
824  /* exit early */
825  return TRUE;
826  }
827  g_hash_table_replace(recurring_actions, op->id, op);
828  }
829 
830  if (is_not_set(op->flags, SVC_ACTION_NON_BLOCKED)
831  && op->rsc && is_op_blocked(op->rsc)) {
832  blocked_ops = g_list_append(blocked_ops, op);
833  return TRUE;
834  }
835 
836  return action_exec_helper(op);
837 }
838 
839 gboolean
841  void (*action_callback) (svc_action_t *))
842 {
843  return services_action_async_fork_notify(op, action_callback, NULL);
844 }
845 
846 static gboolean processing_blocked_ops = FALSE;
847 
848 gboolean
849 is_op_blocked(const char *rsc)
850 {
851  GList *gIter = NULL;
852  svc_action_t *op = NULL;
853 
854  for (gIter = inflight_ops; gIter != NULL; gIter = gIter->next) {
855  op = gIter->data;
856  if (safe_str_eq(op->rsc, rsc)) {
857  return TRUE;
858  }
859  }
860 
861  return FALSE;
862 }
863 
864 static void
865 handle_blocked_ops(void)
866 {
867  GList *executed_ops = NULL;
868  GList *gIter = NULL;
869  svc_action_t *op = NULL;
870  gboolean res = FALSE;
871 
872  if (processing_blocked_ops) {
873  /* avoid nested calling of this function */
874  return;
875  }
876 
877  processing_blocked_ops = TRUE;
878 
879  /* n^2 operation here, but blocked ops are incredibly rare. this list
880  * will be empty 99% of the time. */
881  for (gIter = blocked_ops; gIter != NULL; gIter = gIter->next) {
882  op = gIter->data;
883  if (is_op_blocked(op->rsc)) {
884  continue;
885  }
886  executed_ops = g_list_append(executed_ops, op);
887  res = action_exec_helper(op);
888  if (res == FALSE) {
890  /* this can cause this function to be called recursively
891  * which is why we have processing_blocked_ops static variable */
892  operation_finalize(op);
893  }
894  }
895 
896  for (gIter = executed_ops; gIter != NULL; gIter = gIter->next) {
897  op = gIter->data;
898  blocked_ops = g_list_remove(blocked_ops, op);
899  }
900  g_list_free(executed_ops);
901 
902  processing_blocked_ops = FALSE;
903 }
904 
905 #define lsb_metadata_template \
906  "<?xml version='1.0'?>\n" \
907  "<!DOCTYPE resource-agent SYSTEM 'ra-api-1.dtd'>\n" \
908  "<resource-agent name='%s' version='" PCMK_DEFAULT_AGENT_VERSION "'>\n" \
909  " <version>1.0</version>\n" \
910  " <longdesc lang='en'>\n" \
911  "%s" \
912  " </longdesc>\n" \
913  " <shortdesc lang='en'>%s</shortdesc>\n" \
914  " <parameters>\n" \
915  " </parameters>\n" \
916  " <actions>\n" \
917  " <action name='meta-data' timeout='5' />\n" \
918  " <action name='start' timeout='15' />\n" \
919  " <action name='stop' timeout='15' />\n" \
920  " <action name='status' timeout='15' />\n" \
921  " <action name='restart' timeout='15' />\n" \
922  " <action name='force-reload' timeout='15' />\n" \
923  " <action name='monitor' timeout='15' interval='15' />\n" \
924  " </actions>\n" \
925  " <special tag='LSB'>\n" \
926  " <Provides>%s</Provides>\n" \
927  " <Required-Start>%s</Required-Start>\n" \
928  " <Required-Stop>%s</Required-Stop>\n" \
929  " <Should-Start>%s</Should-Start>\n" \
930  " <Should-Stop>%s</Should-Stop>\n" \
931  " <Default-Start>%s</Default-Start>\n" \
932  " <Default-Stop>%s</Default-Stop>\n" \
933  " </special>\n" \
934  "</resource-agent>\n"
935 
936 /* See "Comment Conventions for Init Scripts" in the LSB core specification at:
937  * http://refspecs.linuxfoundation.org/lsb.shtml
938  */
939 #define LSB_INITSCRIPT_INFOBEGIN_TAG "### BEGIN INIT INFO"
940 #define LSB_INITSCRIPT_INFOEND_TAG "### END INIT INFO"
941 #define PROVIDES "# Provides:"
942 #define REQ_START "# Required-Start:"
943 #define REQ_STOP "# Required-Stop:"
944 #define SHLD_START "# Should-Start:"
945 #define SHLD_STOP "# Should-Stop:"
946 #define DFLT_START "# Default-Start:"
947 #define DFLT_STOP "# Default-Stop:"
948 #define SHORT_DSCR "# Short-Description:"
949 #define DESCRIPTION "# Description:"
950 
951 #define lsb_meta_helper_free_value(m) \
952  do { \
953  if ((m) != NULL) { \
954  xmlFree(m); \
955  (m) = NULL; \
956  } \
957  } while(0)
958 
969 static inline gboolean
970 lsb_meta_helper_get_value(const char *line, char **value, const char *prefix)
971 {
972  if (!*value && crm_starts_with(line, prefix)) {
973  *value = (char *)xmlEncodeEntitiesReentrant(NULL, BAD_CAST line+strlen(prefix));
974  return TRUE;
975  }
976  return FALSE;
977 }
978 
979 #define DESC_MAX 2048
980 
981 static int
982 lsb_get_metadata(const char *type, char **output)
983 {
984  char ra_pathname[PATH_MAX] = { 0, };
985  FILE *fp = NULL;
986  char buffer[1024] = { 0, };
987  char *provides = NULL;
988  char *req_start = NULL;
989  char *req_stop = NULL;
990  char *shld_start = NULL;
991  char *shld_stop = NULL;
992  char *dflt_start = NULL;
993  char *dflt_stop = NULL;
994  char *s_dscrpt = NULL;
995  char *xml_l_dscrpt = NULL;
996  int offset = 0;
997  bool in_header = FALSE;
998  char description[DESC_MAX] = { 0, };
999 
1000  if (type[0] == '/') {
1001  snprintf(ra_pathname, sizeof(ra_pathname), "%s", type);
1002  } else {
1003  snprintf(ra_pathname, sizeof(ra_pathname), "%s/%s",
1004  LSB_ROOT_DIR, type);
1005  }
1006 
1007  crm_trace("Looking into %s", ra_pathname);
1008  fp = fopen(ra_pathname, "r");
1009  if (fp == NULL) {
1010  return -errno;
1011  }
1012 
1013  /* Enter into the LSB-compliant comment block */
1014  while (fgets(buffer, sizeof(buffer), fp)) {
1015 
1016  // Ignore lines up to and including the block delimiter
1018  in_header = TRUE;
1019  continue;
1020  }
1021  if (!in_header) {
1022  continue;
1023  }
1024 
1025  /* Assume each of the following eight arguments contain one line */
1026  if (lsb_meta_helper_get_value(buffer, &provides, PROVIDES)) {
1027  continue;
1028  }
1029  if (lsb_meta_helper_get_value(buffer, &req_start, REQ_START)) {
1030  continue;
1031  }
1032  if (lsb_meta_helper_get_value(buffer, &req_stop, REQ_STOP)) {
1033  continue;
1034  }
1035  if (lsb_meta_helper_get_value(buffer, &shld_start, SHLD_START)) {
1036  continue;
1037  }
1038  if (lsb_meta_helper_get_value(buffer, &shld_stop, SHLD_STOP)) {
1039  continue;
1040  }
1041  if (lsb_meta_helper_get_value(buffer, &dflt_start, DFLT_START)) {
1042  continue;
1043  }
1044  if (lsb_meta_helper_get_value(buffer, &dflt_stop, DFLT_STOP)) {
1045  continue;
1046  }
1047  if (lsb_meta_helper_get_value(buffer, &s_dscrpt, SHORT_DSCR)) {
1048  continue;
1049  }
1050 
1051  /* Long description may cross multiple lines */
1052  if ((offset == 0) // haven't already found long description
1053  && crm_starts_with(buffer, DESCRIPTION)) {
1054  bool processed_line = TRUE;
1055 
1056  // Get remainder of description line itself
1057  offset += snprintf(description, DESC_MAX, "%s",
1058  buffer + strlen(DESCRIPTION));
1059 
1060  // Read any continuation lines of the description
1061  buffer[0] = '\0';
1062  while (fgets(buffer, sizeof(buffer), fp)) {
1063  if (crm_starts_with(buffer, "# ")
1064  || crm_starts_with(buffer, "#\t")) {
1065  /* '#' followed by a tab or more than one space indicates a
1066  * continuation of the long description.
1067  */
1068  offset += snprintf(description + offset, DESC_MAX - offset,
1069  "%s", buffer + 1);
1070  } else {
1071  /* This line is not part of the long description,
1072  * so continue with normal processing.
1073  */
1074  processed_line = FALSE;
1075  break;
1076  }
1077  }
1078 
1079  // Make long description safe to use in XML
1080  xml_l_dscrpt = (char *)xmlEncodeEntitiesReentrant(NULL, BAD_CAST(description));
1081 
1082  if (processed_line) {
1083  // We grabbed the line into the long description
1084  continue;
1085  }
1086  }
1087 
1088  // Stop if we leave the header block
1090  break;
1091  }
1092  if (buffer[0] != '#') {
1093  break;
1094  }
1095  }
1096  fclose(fp);
1097 
1098  *output = crm_strdup_printf(lsb_metadata_template, type,
1099  (xml_l_dscrpt? xml_l_dscrpt : type),
1100  (s_dscrpt? s_dscrpt : type),
1101  (provides? provides : ""),
1102  (req_start? req_start : ""),
1103  (req_stop? req_stop : ""),
1104  (shld_start? shld_start : ""),
1105  (shld_stop? shld_stop : ""),
1106  (dflt_start? dflt_start : ""),
1107  (dflt_stop? dflt_stop : ""));
1108 
1109  lsb_meta_helper_free_value(xml_l_dscrpt);
1110  lsb_meta_helper_free_value(s_dscrpt);
1111  lsb_meta_helper_free_value(provides);
1112  lsb_meta_helper_free_value(req_start);
1113  lsb_meta_helper_free_value(req_stop);
1114  lsb_meta_helper_free_value(shld_start);
1115  lsb_meta_helper_free_value(shld_stop);
1116  lsb_meta_helper_free_value(dflt_start);
1117  lsb_meta_helper_free_value(dflt_stop);
1118 
1119  crm_trace("Created fake metadata: %llu",
1120  (unsigned long long) strlen(*output));
1121  return pcmk_ok;
1122 }
1123 
1124 #if SUPPORT_NAGIOS
1125 static int
1126 nagios_get_metadata(const char *type, char **output)
1127 {
1128  int rc = pcmk_ok;
1129  FILE *file_strm = NULL;
1130  int start = 0, length = 0, read_len = 0;
1131  char *metadata_file = crm_strdup_printf("%s/%s.xml",
1132  NAGIOS_METADATA_DIR, type);
1133 
1134  file_strm = fopen(metadata_file, "r");
1135  if (file_strm == NULL) {
1136  crm_err("Metadata file %s does not exist", metadata_file);
1137  free(metadata_file);
1138  return -EIO;
1139  }
1140 
1141  /* see how big the file is */
1142  start = ftell(file_strm);
1143  fseek(file_strm, 0L, SEEK_END);
1144  length = ftell(file_strm);
1145  fseek(file_strm, 0L, start);
1146 
1147  CRM_ASSERT(length >= 0);
1148  CRM_ASSERT(start == ftell(file_strm));
1149 
1150  if (length <= 0) {
1151  crm_info("%s was not valid", metadata_file);
1152  free(*output);
1153  *output = NULL;
1154  rc = -EIO;
1155 
1156  } else {
1157  crm_trace("Reading %d bytes from file", length);
1158  *output = calloc(1, (length + 1));
1159  read_len = fread(*output, 1, length, file_strm);
1160  if (read_len != length) {
1161  crm_err("Calculated and read bytes differ: %d vs. %d",
1162  length, read_len);
1163  free(*output);
1164  *output = NULL;
1165  rc = -EIO;
1166  }
1167  }
1168 
1169  fclose(file_strm);
1170  free(metadata_file);
1171  return rc;
1172 }
1173 #endif
1174 
1175 #if SUPPORT_HEARTBEAT
1176 /* strictly speaking, support for class=heartbeat style scripts
1177  * does not require "heartbeat support" to be enabled.
1178  * But since those scripts are part of the "heartbeat" package usually,
1179  * and are very unlikely to be present in any other deployment,
1180  * I leave it inside this ifdef.
1181  *
1182  * Yes, I know, these are legacy and should die,
1183  * or at least be rewritten to be a proper OCF style agent.
1184  * But they exist, and custom scripts following these rules do, too.
1185  *
1186  * Taken from the old "glue" lrmd, see
1187  * http://hg.linux-ha.org/glue/file/0a7add1d9996/lib/plugins/lrm/raexechb.c#l49
1188  * http://hg.linux-ha.org/glue/file/0a7add1d9996/lib/plugins/lrm/raexechb.c#l393
1189  */
1190 
1191 static const char hb_metadata_template[] =
1192  "<?xml version='1.0'?>\n"
1193  "<!DOCTYPE resource-agent SYSTEM 'ra-api-1.dtd'>\n"
1194  "<resource-agent name='%s' version='" PCMK_DEFAULT_AGENT_VERSION "'>\n"
1195  "<version>1.0</version>\n"
1196  "<longdesc lang='en'>\n"
1197  "%s"
1198  "</longdesc>\n"
1199  "<shortdesc lang='en'>%s</shortdesc>\n"
1200  "<parameters>\n"
1201  "<parameter name='1' unique='1' required='0'>\n"
1202  "<longdesc lang='en'>\n"
1203  "This argument will be passed as the first argument to the "
1204  "heartbeat resource agent (assuming it supports one)\n"
1205  "</longdesc>\n"
1206  "<shortdesc lang='en'>argv[1]</shortdesc>\n"
1207  "<content type='string' default=' ' />\n"
1208  "</parameter>\n"
1209  "<parameter name='2' unique='1' required='0'>\n"
1210  "<longdesc lang='en'>\n"
1211  "This argument will be passed as the second argument to the "
1212  "heartbeat resource agent (assuming it supports one)\n"
1213  "</longdesc>\n"
1214  "<shortdesc lang='en'>argv[2]</shortdesc>\n"
1215  "<content type='string' default=' ' />\n"
1216  "</parameter>\n"
1217  "<parameter name='3' unique='1' required='0'>\n"
1218  "<longdesc lang='en'>\n"
1219  "This argument will be passed as the third argument to the "
1220  "heartbeat resource agent (assuming it supports one)\n"
1221  "</longdesc>\n"
1222  "<shortdesc lang='en'>argv[3]</shortdesc>\n"
1223  "<content type='string' default=' ' />\n"
1224  "</parameter>\n"
1225  "<parameter name='4' unique='1' required='0'>\n"
1226  "<longdesc lang='en'>\n"
1227  "This argument will be passed as the fourth argument to the "
1228  "heartbeat resource agent (assuming it supports one)\n"
1229  "</longdesc>\n"
1230  "<shortdesc lang='en'>argv[4]</shortdesc>\n"
1231  "<content type='string' default=' ' />\n"
1232  "</parameter>\n"
1233  "<parameter name='5' unique='1' required='0'>\n"
1234  "<longdesc lang='en'>\n"
1235  "This argument will be passed as the fifth argument to the "
1236  "heartbeat resource agent (assuming it supports one)\n"
1237  "</longdesc>\n"
1238  "<shortdesc lang='en'>argv[5]</shortdesc>\n"
1239  "<content type='string' default=' ' />\n"
1240  "</parameter>\n"
1241  "</parameters>\n"
1242  "<actions>\n"
1243  "<action name='start' timeout='15' />\n"
1244  "<action name='stop' timeout='15' />\n"
1245  "<action name='status' timeout='15' />\n"
1246  "<action name='monitor' timeout='15' interval='15' start-delay='15' />\n"
1247  "<action name='meta-data' timeout='5' />\n"
1248  "</actions>\n"
1249  "<special tag='heartbeat'>\n"
1250  "</special>\n"
1251  "</resource-agent>\n";
1252 
1253 static int
1254 heartbeat_get_metadata(const char *type, char **output)
1255 {
1256  *output = crm_strdup_printf(hb_metadata_template, type, type, type);
1257  crm_trace("Created fake metadata: %llu",
1258  (unsigned long long) strlen(*output));
1259  return pcmk_ok;
1260 }
1261 #endif
1262 
1263 static gboolean
1264 action_get_metadata(svc_action_t *op)
1265 {
1266  const char *class = op->standard;
1267 
1268  if (op->agent == NULL) {
1269  crm_err("meta-data requested without specifying agent");
1270  return FALSE;
1271  }
1272 
1273  if (class == NULL) {
1274  crm_err("meta-data requested for agent %s without specifying class",
1275  op->agent);
1276  return FALSE;
1277  }
1278 
1279  if (!strcmp(class, PCMK_RESOURCE_CLASS_SERVICE)) {
1280  class = resources_find_service_class(op->agent);
1281  }
1282 
1283  if (class == NULL) {
1284  crm_err("meta-data requested for %s, but could not determine class",
1285  op->agent);
1286  return FALSE;
1287  }
1288 
1289  if (safe_str_eq(class, PCMK_RESOURCE_CLASS_LSB)) {
1290  return (lsb_get_metadata(op->agent, &op->stdout_data) >= 0);
1291  }
1292 
1293 #if SUPPORT_NAGIOS
1295  return (nagios_get_metadata(op->agent, &op->stdout_data) >= 0);
1296  }
1297 #endif
1298 
1299 #if SUPPORT_HEARTBEAT
1300  if (safe_str_eq(class, PCMK_RESOURCE_CLASS_HB)) {
1301  return (heartbeat_get_metadata(op->agent, &op->stdout_data) >= 0);
1302  }
1303 #endif
1304 
1305  return action_exec_helper(op);
1306 }
1307 
1308 gboolean
1310 {
1311  gboolean rc = TRUE;
1312 
1313  if (op == NULL) {
1314  crm_trace("No operation to execute");
1315  return FALSE;
1316  }
1317 
1318  op->synchronous = true;
1319 
1320  if (safe_str_eq(op->action, "meta-data")) {
1321  /* Synchronous meta-data operations are handled specially. Since most
1322  * resource classes don't provide any meta-data, it has to be
1323  * synthesized from available information about the agent.
1324  *
1325  * services_action_async() doesn't treat meta-data actions specially, so
1326  * it will result in an error for classes that don't support the action.
1327  */
1328  rc = action_get_metadata(op);
1329  } else {
1330  rc = action_exec_helper(op);
1331  }
1332  crm_trace(" > %s_%s_%d: %s = %d",
1333  op->rsc, op->action, op->interval, op->opaque->exec, op->rc);
1334  if (op->stdout_data) {
1335  crm_trace(" > stdout: %s", op->stdout_data);
1336  }
1337  if (op->stderr_data) {
1338  crm_trace(" > stderr: %s", op->stderr_data);
1339  }
1340  return rc;
1341 }
1342 
1343 GList *
1344 get_directory_list(const char *root, gboolean files, gboolean executable)
1345 {
1346  return services_os_get_directory_list(root, files, executable);
1347 }
1348 
1349 GList *
1351 {
1353 }
1354 
1355 #if SUPPORT_HEARTBEAT
1356 static GList *
1357 resources_os_list_hb_agents(void)
1358 {
1359  return services_os_get_directory_list(HB_RA_DIR, TRUE, TRUE);
1360 }
1361 #endif
1362 
1363 GList *
1365 {
1366  GList *standards = NULL;
1367  GList *agents = NULL;
1368 
1369  standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_OCF));
1370  standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_LSB));
1371  standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_SERVICE));
1372 
1373 #if SUPPORT_SYSTEMD
1374  agents = systemd_unit_listall();
1375  if (agents) {
1376  standards = g_list_append(standards,
1377  strdup(PCMK_RESOURCE_CLASS_SYSTEMD));
1378  g_list_free_full(agents, free);
1379  }
1380 #endif
1381 
1382 #if SUPPORT_UPSTART
1383  agents = upstart_job_listall();
1384  if (agents) {
1385  standards = g_list_append(standards,
1386  strdup(PCMK_RESOURCE_CLASS_UPSTART));
1387  g_list_free_full(agents, free);
1388  }
1389 #endif
1390 
1391 #if SUPPORT_NAGIOS
1393  if (agents) {
1394  standards = g_list_append(standards,
1395  strdup(PCMK_RESOURCE_CLASS_NAGIOS));
1396  g_list_free_full(agents, free);
1397  }
1398 #endif
1399 
1400 #if SUPPORT_HEARTBEAT
1401  standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_HB));
1402 #endif
1403 
1404  return standards;
1405 }
1406 
1407 GList *
1408 resources_list_providers(const char *standard)
1409 {
1410  if (is_set(pcmk_get_ra_caps(standard), pcmk_ra_cap_provider)) {
1412  }
1413 
1414  return NULL;
1415 }
1416 
1417 GList *
1418 resources_list_agents(const char *standard, const char *provider)
1419 {
1420  if ((standard == NULL)
1421  || (strcasecmp(standard, PCMK_RESOURCE_CLASS_SERVICE) == 0)) {
1422 
1423  GList *tmp1;
1424  GList *tmp2;
1425  GList *result = resources_os_list_lsb_agents();
1426 
1427  if (standard == NULL) {
1428  tmp1 = result;
1429  tmp2 = resources_os_list_ocf_agents(NULL);
1430  if (tmp2) {
1431  result = g_list_concat(tmp1, tmp2);
1432  }
1433  }
1434 #if SUPPORT_SYSTEMD
1435  tmp1 = result;
1436  tmp2 = systemd_unit_listall();
1437  if (tmp2) {
1438  result = g_list_concat(tmp1, tmp2);
1439  }
1440 #endif
1441 
1442 #if SUPPORT_UPSTART
1443  tmp1 = result;
1444  tmp2 = upstart_job_listall();
1445  if (tmp2) {
1446  result = g_list_concat(tmp1, tmp2);
1447  }
1448 #endif
1449 
1450  return result;
1451 
1452  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_OCF) == 0) {
1453  return resources_os_list_ocf_agents(provider);
1454  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_LSB) == 0) {
1456 #if SUPPORT_HEARTBEAT
1457  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_HB) == 0) {
1458  return resources_os_list_hb_agents();
1459 #endif
1460 #if SUPPORT_SYSTEMD
1461  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_SYSTEMD) == 0) {
1462  return systemd_unit_listall();
1463 #endif
1464 #if SUPPORT_UPSTART
1465  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_UPSTART) == 0) {
1466  return upstart_job_listall();
1467 #endif
1468 #if SUPPORT_NAGIOS
1469  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_NAGIOS) == 0) {
1471 #endif
1472  }
1473 
1474  return NULL;
1475 }
gboolean services_action_cancel(const char *name, const char *action, int interval)
Cancel a recurring action.
Definition: services.c:618
Services API.
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:190
#define lsb_metadata_template
Definition: services.c:905
void(* callback)(svc_action_t *op)
A dumping ground.
#define SHORT_DSCR
Definition: services.c:948
GList * resources_list_providers(const char *standard)
Get a list of providers.
Definition: services.c:1408
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:808
char * standard
Definition: services.h:169
gboolean upstart_job_exists(const char *name)
Definition: upstart.c:230
gboolean mainloop_child_kill(pid_t pid)
Definition: mainloop.c:1118
char * id
Definition: services.h:164
svc_action_t * resources_action_create(const char *name, const char *standard, const char *provider, const char *agent, const char *action, int interval, int timeout, GHashTable *params, enum svc_action_flags flags)
Create a new resource action.
Definition: services.c:175
mainloop_io_t * stderr_gsource
GList * resources_os_list_ocf_agents(const char *provider)
GList * resources_os_list_ocf_providers(void)
#define PCMK_RESOURCE_CLASS_SYSTEMD
Definition: services.h:60
#define pcmk_ok
Definition: error.h:45
#define PROVIDES
Definition: services.c:941
gboolean recurring_action_timer(gpointer data)
GList * services_os_get_directory_list(const char *root, gboolean files, gboolean executable)
gboolean services_action_async(svc_action_t *op, void(*action_callback)(svc_action_t *))
Definition: services.c:840
char * rsc
Definition: services.h:165
int crm_user_lookup(const char *name, uid_t *uid, gid_t *gid)
Definition: utils.c:424
int interval
Definition: services.h:167
gboolean services_os_action_execute(svc_action_t *op)
G_GNUC_INTERNAL GList * resources_os_list_nagios_agents(void)
#define DESCRIPTION
Definition: services.c:949
svc_action_flags
Definition: services.h:156
#define DESC_MAX
Definition: services.c:979
gboolean upstart_job_exec(svc_action_t *op)
Definition: upstart.c:417
gboolean is_op_blocked(const char *rsc)
Definition: services.c:849
Wrappers for and extensions to glib mainloop.
bool crm_starts_with(const char *str, const char *prefix)
Check whether a string starts with a certain sequence.
Definition: strings.c:284
svc_action_t * services_action_create_generic(const char *exec, const char *args[])
Definition: services.c:379
GList * resources_os_list_lsb_agents(void)
#define SHLD_START
Definition: services.c:944
enum svc_action_flags flags
Definition: services.h:186
#define crm_warn(fmt, args...)
Definition: logging.h:275
GList * services_list(void)
Definition: services.c:1350
#define PCMK_RESOURCE_CLASS_OCF
Definition: services.h:57
gboolean cancel_recurring_action(svc_action_t *op)
Definition: services.c:592
svc_action_private_t * opaque
Definition: services.h:199
GList * upstart_job_listall(void)
Definition: upstart.c:149
#define OCF_ROOT_DIR
Definition: services.h:39
#define crm_debug(fmt, args...)
Definition: logging.h:279
#define REQ_START
Definition: services.c:942
gboolean operation_finalize(svc_action_t *op)
char * stdout_data
Definition: services.h:189
svc_action_t * services_alert_create(const char *id, const char *exec, int timeout, GHashTable *params, int sequence, void *cb_data)
Create an alert agent action.
Definition: services.c:417
gboolean systemd_unit_exists(const char *name)
Definition: systemd.c:459
#define PCMK_RESOURCE_CLASS_SERVICE
Definition: services.h:58
GHashTable * params
Definition: services.h:174
#define LSB_INITSCRIPT_INFOEND_TAG
Definition: services.c:940
#define crm_trace(fmt, args...)
Definition: logging.h:280
gboolean services_alert_async(svc_action_t *action, void(*cb)(svc_action_t *op))
Execute an alert agent action.
Definition: services.c:465
char * agent
Definition: services.h:171
int synchronous
Definition: services.h:185
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard.
Definition: agents.c:29
#define LSB_INITSCRIPT_INFOBEGIN_TAG
Definition: services.c:939
gboolean services_action_sync(svc_action_t *op)
Definition: services.c:1309
#define LSB_ROOT_DIR
Definition: services.h:43
int sequence
Definition: services.h:183
#define SHLD_STOP
Definition: services.c:945
gboolean services_action_kick(const char *name, const char *action, int interval)
Definition: services.c:685
GList * systemd_unit_listall(void)
Definition: systemd.c:362
const char * resources_find_service_class(const char *agent)
Find first service class that can provide a specified agent.
Definition: services.c:89
GList * resources_list_agents(const char *standard, const char *provider)
Get a list of resource agents.
Definition: services.c:1418
#define MAX_ARGC
char * args[MAX_ARGC]
void services_add_inflight_op(svc_action_t *op)
Definition: services.c:776
GList * resources_list_standards(void)
Definition: services.c:1364
void services_untrack_op(svc_action_t *op)
Definition: services.c:797
char * action
Definition: services.h:166
GList * get_directory_list(const char *root, gboolean files, gboolean executable)
Get a list of files or directories in a given path.
Definition: services.c:1344
#define PCMK_RESOURCE_CLASS_NAGIOS
Definition: services.h:63
#define PCMK_RESOURCE_CLASS_LSB
Definition: services.h:59
#define NAGIOS_PLUGIN_DIR
Definition: config.h:624
#define CRM_META
Definition: crm.h:43
#define crm_err(fmt, args...)
Definition: logging.h:274
#define PCMK_RESOURCE_CLASS_UPSTART
Definition: services.h:61
#define PCMK_RESOURCE_CLASS_HB
Definition: services.h:62
int services_action_user(svc_action_t *op, const char *user)
Set the user and group that an action will execute as.
Definition: services.c:447
#define PCMK_DEFAULT_AGENT_VERSION
Definition: services.h:73
#define DIMOF(a)
Definition: crm.h:29
#define uint32_t
Definition: stdint.in.h:158
mainloop_io_t * stdout_gsource
#define CRM_ASSERT(expr)
Definition: error.h:20
#define XML_ATTR_CRM_VERSION
Definition: msg_xml.h:84
#define REQ_STOP
Definition: services.c:943
#define DFLT_STOP
Definition: services.c:947
void mainloop_del_fd(mainloop_io_t *client)
Definition: mainloop.c:930
void * cb_data
Definition: services.h:197
void services_action_cleanup(svc_action_t *op)
Definition: services.c:501
char * generate_op_key(const char *rsc_id, const char *op_type, int interval)
Generate an operation key.
Definition: operations.c:37
#define safe_str_eq(a, b)
Definition: util.h:74
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
void services_action_free(svc_action_t *op)
Definition: services.c:540
#define DFLT_START
Definition: services.c:946
char * provider
Definition: services.h:170
void(* fork_callback)(svc_action_t *op)
gboolean systemd_unit_exec(svc_action_t *op)
Definition: systemd.c:798
#define crm_info(fmt, args...)
Definition: logging.h:277
#define NAGIOS_METADATA_DIR
Definition: config.h:621
uint64_t flags
Definition: remote.c:156
svc_action_t * services_action_create(const char *name, const char *action, int interval, int timeout)
Definition: services.c:52
enum crm_ais_msg_types type
Definition: internal.h:79
#define lsb_meta_helper_free_value(m)
Definition: services.c:951
char * stderr_data
Definition: services.h:188