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