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