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