pacemaker  1.1.14-70404b0
Scalable High-Availability cluster resource manager
services.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2010 Andrew Beekhof <andrew@beekhof.net>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This software is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  */
18 
19 #include <crm_internal.h>
20 
21 #ifndef _GNU_SOURCE
22 # define _GNU_SOURCE
23 #endif
24 
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <stdio.h>
28 
29 #include <errno.h>
30 #include <unistd.h>
31 #include <dirent.h>
32 #include <fcntl.h>
33 
34 #include <crm/crm.h>
35 #include <crm/common/mainloop.h>
36 #include <crm/services.h>
37 #include <crm/msg_xml.h>
38 #include "services_private.h"
39 
40 #if SUPPORT_UPSTART
41 # include <upstart.h>
42 #endif
43 
44 #if SUPPORT_SYSTEMD
45 # include <systemd.h>
46 #endif
47 
48 /* TODO: Develop a rollover strategy */
49 
50 static int operations = 0;
51 GHashTable *recurring_actions = NULL;
52 
53 /* ops waiting to run async because of conflicting active
54  * pending ops*/
55 GList *blocked_ops = NULL;
56 
57 /* ops currently active (in-flight) */
58 GList *inflight_ops = NULL;
59 
61 services_action_create(const char *name, const char *action, int interval, int timeout)
62 {
63  return resources_action_create(name, "lsb", NULL, name, action, interval, timeout, NULL, 0);
64 }
65 
66 const char *
67 resources_find_service_class(const char *agent)
68 {
69  /* Priority is:
70  * - lsb
71  * - systemd
72  * - upstart
73  */
74  int rc = 0;
75  struct stat st;
76  char *path = NULL;
77 
78 #ifdef LSB_ROOT_DIR
79  rc = asprintf(&path, "%s/%s", LSB_ROOT_DIR, agent);
80  if (rc > 0 && stat(path, &st) == 0) {
81  free(path);
82  return "lsb";
83  }
84  free(path);
85 #endif
86 
87 #if SUPPORT_SYSTEMD
88  if (systemd_unit_exists(agent)) {
89  return "systemd";
90  }
91 #endif
92 
93 #if SUPPORT_UPSTART
94  if (upstart_job_exists(agent)) {
95  return "upstart";
96  }
97 #endif
98  return NULL;
99 }
100 
109 static inline gboolean
110 inflight_systemd_or_upstart(svc_action_t *op)
111 {
112  return (safe_str_eq(op->standard, "systemd")
113  || safe_str_eq(op->standard, "upstart"))
114  && (g_list_find(inflight_ops, op) != NULL);
115 }
116 
117 svc_action_t *
118 resources_action_create(const char *name, const char *standard, const char *provider,
119  const char *agent, const char *action, int interval, int timeout,
120  GHashTable * params, enum svc_action_flags flags)
121 {
122  svc_action_t *op = NULL;
123 
124  /*
125  * Do some up front sanity checks before we go off and
126  * build the svc_action_t instance.
127  */
128 
129  if (crm_strlen_zero(name)) {
130  crm_err("A service or resource action must have a name.");
131  goto return_error;
132  }
133 
134  if (crm_strlen_zero(standard)) {
135  crm_err("A service action must have a valid standard.");
136  goto return_error;
137  }
138 
139  if (!strcasecmp(standard, "ocf") && crm_strlen_zero(provider)) {
140  crm_err("An OCF resource action must have a provider.");
141  goto return_error;
142  }
143 
144  if (crm_strlen_zero(agent)) {
145  crm_err("A service or resource action must have an agent.");
146  goto return_error;
147  }
148 
149  if (crm_strlen_zero(action)) {
150  crm_err("A service or resource action must specify an action.");
151  goto return_error;
152  }
153 
154  if (safe_str_eq(action, "monitor") && (
156  safe_str_eq(standard, "heartbeat") ||
157 #endif
158  safe_str_eq(standard, "lsb") || safe_str_eq(standard, "service"))) {
159  action = "status";
160  }
161 
162  /*
163  * Sanity checks passed, proceed!
164  */
165 
166  op = calloc(1, sizeof(svc_action_t));
167  op->opaque = calloc(1, sizeof(svc_action_private_t));
168  op->rsc = strdup(name);
169  op->action = strdup(action);
170  op->interval = interval;
171  op->timeout = timeout;
172  op->standard = strdup(standard);
173  op->agent = strdup(agent);
174  op->sequence = ++operations;
175  op->flags = flags;
176 
177  if (asprintf(&op->id, "%s_%s_%d", name, action, interval) == -1) {
178  goto return_error;
179  }
180 
181  if (strcasecmp(op->standard, "service") == 0) {
182  const char *expanded = resources_find_service_class(op->agent);
183 
184  if(expanded) {
185  crm_debug("Found a %s agent for %s/%s", expanded, op->rsc, op->agent);
186  free(op->standard);
187  op->standard = strdup(expanded);
188 
189  } else {
190  crm_info("Cannot determine the standard for %s (%s)", op->rsc, op->agent);
191  free(op->standard);
192  op->standard = strdup("lsb");
193  }
194  CRM_ASSERT(op->standard);
195  }
196 
197  if (strcasecmp(op->standard, "ocf") == 0) {
198  op->provider = strdup(provider);
199  op->params = params;
200  params = NULL;
201 
202  if (asprintf(&op->opaque->exec, "%s/resource.d/%s/%s", OCF_ROOT_DIR, provider, agent) == -1) {
203  crm_err("Internal error: cannot create agent path");
204  goto return_error;
205  }
206  op->opaque->args[0] = strdup(op->opaque->exec);
207  op->opaque->args[1] = strdup(action);
208 
209  } else if (strcasecmp(op->standard, "lsb") == 0) {
210  if (op->agent[0] == '/') {
211  /* if given an absolute path, use that instead
212  * of tacking on the LSB_ROOT_DIR path to the front */
213  op->opaque->exec = strdup(op->agent);
214  } else if (asprintf(&op->opaque->exec, "%s/%s", LSB_ROOT_DIR, op->agent) == -1) {
215  crm_err("Internal error: cannot create agent path");
216  goto return_error;
217  }
218  op->opaque->args[0] = strdup(op->opaque->exec);
219  op->opaque->args[1] = strdup(op->action);
220  op->opaque->args[2] = NULL;
221 #if SUPPORT_HEARTBEAT
222  } else if (strcasecmp(op->standard, "heartbeat") == 0) {
223  int index;
224  int param_num;
225  char buf_tmp[20];
226  void *value_tmp;
227 
228  if (op->agent[0] == '/') {
229  /* if given an absolute path, use that instead
230  * of tacking on the HB_RA_DIR path to the front */
231  op->opaque->exec = strdup(op->agent);
232  } else if (asprintf(&op->opaque->exec, "%s/%s", HB_RA_DIR, op->agent) == -1) {
233  crm_err("Internal error: cannot create agent path");
234  goto return_error;
235  }
236  op->opaque->args[0] = strdup(op->opaque->exec);
237 
238  /* The "heartbeat" agent class only has positional arguments,
239  * which we keyed by their decimal position number. */
240  param_num = 1;
241  for (index = 1; index <= MAX_ARGC - 3; index++ ) {
242  snprintf(buf_tmp, sizeof(buf_tmp), "%d", index);
243  value_tmp = g_hash_table_lookup(params, buf_tmp);
244  if (value_tmp == NULL) {
245  /* maybe: strdup("") ??
246  * But the old lrmd did simply continue as well. */
247  continue;
248  }
249  op->opaque->args[param_num++] = strdup(value_tmp);
250  }
251 
252  /* Add operation code as the last argument, */
253  /* and the teminating NULL pointer */
254  op->opaque->args[param_num++] = strdup(op->action);
255  op->opaque->args[param_num] = NULL;
256 #endif
257 #if SUPPORT_SYSTEMD
258  } else if (strcasecmp(op->standard, "systemd") == 0) {
259  op->opaque->exec = strdup("systemd-dbus");
260 #endif
261 #if SUPPORT_UPSTART
262  } else if (strcasecmp(op->standard, "upstart") == 0) {
263  op->opaque->exec = strdup("upstart-dbus");
264 #endif
265  } else if (strcasecmp(op->standard, "service") == 0) {
266  op->opaque->exec = strdup(SERVICE_SCRIPT);
267  op->opaque->args[0] = strdup(SERVICE_SCRIPT);
268  op->opaque->args[1] = strdup(agent);
269  op->opaque->args[2] = strdup(action);
270 
271 #if SUPPORT_NAGIOS
272  } else if (strcasecmp(op->standard, "nagios") == 0) {
273  int index = 0;
274 
275  if (op->agent[0] == '/') {
276  /* if given an absolute path, use that instead
277  * of tacking on the NAGIOS_PLUGIN_DIR path to the front */
278  op->opaque->exec = strdup(op->agent);
279 
280  } else if (asprintf(&op->opaque->exec, "%s/%s", NAGIOS_PLUGIN_DIR, op->agent) == -1) {
281  crm_err("Internal error: cannot create agent path");
282  goto return_error;
283  }
284 
285  op->opaque->args[0] = strdup(op->opaque->exec);
286  index = 1;
287 
288  if (safe_str_eq(op->action, "monitor") && op->interval == 0) {
289  /* Invoke --version for a nagios probe */
290  op->opaque->args[index] = strdup("--version");
291  index++;
292 
293  } else if (params) {
294  GHashTableIter iter;
295  char *key = NULL;
296  char *value = NULL;
297  static int args_size = sizeof(op->opaque->args) / sizeof(char *);
298 
299  g_hash_table_iter_init(&iter, params);
300 
301  while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value) &&
302  index <= args_size - 3) {
303  int len = 3;
304  char *long_opt = NULL;
305 
306  if (safe_str_eq(key, XML_ATTR_CRM_VERSION) || strstr(key, CRM_META "_")) {
307  continue;
308  }
309 
310  len += strlen(key);
311  long_opt = calloc(1, len);
312  sprintf(long_opt, "--%s", key);
313  long_opt[len - 1] = 0;
314 
315  op->opaque->args[index] = long_opt;
316  op->opaque->args[index + 1] = strdup(value);
317  index += 2;
318  }
319  }
320  op->opaque->args[index] = NULL;
321 #endif
322 
323  } else {
324  crm_err("Unknown resource standard: %s", op->standard);
326  op = NULL;
327  }
328 
329  if(params) {
330  g_hash_table_destroy(params);
331  }
332  return op;
333 
334  return_error:
335  if(params) {
336  g_hash_table_destroy(params);
337  }
339 
340  return NULL;
341 }
342 
343 svc_action_t *
344 services_action_create_generic(const char *exec, const char *args[])
345 {
346  svc_action_t *op;
347  unsigned int cur_arg;
348 
349  op = calloc(1, sizeof(*op));
350  op->opaque = calloc(1, sizeof(svc_action_private_t));
351 
352  op->opaque->exec = strdup(exec);
353  op->opaque->args[0] = strdup(exec);
354 
355  for (cur_arg = 1; args && args[cur_arg - 1]; cur_arg++) {
356  op->opaque->args[cur_arg] = strdup(args[cur_arg - 1]);
357 
358  if (cur_arg == DIMOF(op->opaque->args) - 1) {
359  crm_err("svc_action_t args list not long enough for '%s' execution request.", exec);
360  break;
361  }
362  }
363 
364  return op;
365 }
366 
367 #if SUPPORT_DBUS
368 /*
369  * \internal
370  * \brief Update operation's pending DBus call, unreferencing old one if needed
371  *
372  * \param[in,out] op Operation to modify
373  * \param[in] pending Pending call to set
374  */
375 void
376 services_set_op_pending(svc_action_t *op, DBusPendingCall *pending)
377 {
378  if (op->opaque->pending && (op->opaque->pending != pending)) {
379  if (pending) {
380  crm_info("Lost pending %s DBus call (%p)", op->id, op->opaque->pending);
381  } else {
382  crm_trace("Done with pending %s DBus call (%p)", op->id, op->opaque->pending);
383  }
384  dbus_pending_call_unref(op->opaque->pending);
385  }
386  op->opaque->pending = pending;
387  if (pending) {
388  crm_trace("Updated pending %s DBus call (%p)", op->id, pending);
389  } else {
390  crm_trace("Cleared pending %s DBus call", op->id);
391  }
392 }
393 #endif
394 
395 void
397 {
398 #if SUPPORT_DBUS
399  if(op->opaque == NULL) {
400  return;
401  }
402 
403  if(op->opaque->timerid != 0) {
404  crm_trace("Removing timer for call %s to %s", op->action, op->rsc);
405  g_source_remove(op->opaque->timerid);
406  op->opaque->timerid = 0;
407  }
408 
409  if(op->opaque->pending) {
410  crm_trace("Cleaning up pending dbus call %p %s for %s", op->opaque->pending, op->action, op->rsc);
411  if(dbus_pending_call_get_completed(op->opaque->pending)) {
412  crm_warn("Pending dbus call %s for %s did not complete", op->action, op->rsc);
413  }
414  dbus_pending_call_cancel(op->opaque->pending);
415  dbus_pending_call_unref(op->opaque->pending);
416  op->opaque->pending = NULL;
417  }
418 
419  if (op->opaque->stderr_gsource) {
421  op->opaque->stderr_gsource = NULL;
422  }
423 
424  if (op->opaque->stdout_gsource) {
426  op->opaque->stdout_gsource = NULL;
427  }
428 #endif
429 }
430 
431 void
433 {
434  unsigned int i;
435 
436  if (op == NULL) {
437  return;
438  }
439 
440  /* The operation should be removed from all tracking lists by this point.
441  * If it's not, we have a bug somewhere, so bail. That may lead to a
442  * memory leak, but it's better than a use-after-free segmentation fault.
443  */
444  CRM_CHECK(g_list_find(inflight_ops, op) == NULL, return);
445  CRM_CHECK(g_list_find(blocked_ops, op) == NULL, return);
446  CRM_CHECK((recurring_actions == NULL)
447  || (g_hash_table_lookup(recurring_actions, op->id) == NULL),
448  return);
449 
451 
452  if (op->opaque->repeat_timer) {
453  g_source_remove(op->opaque->repeat_timer);
454  op->opaque->repeat_timer = 0;
455  }
456 
457  free(op->id);
458  free(op->opaque->exec);
459 
460  for (i = 0; i < DIMOF(op->opaque->args); i++) {
461  free(op->opaque->args[i]);
462  }
463 
464  free(op->opaque);
465  free(op->rsc);
466  free(op->action);
467 
468  free(op->standard);
469  free(op->agent);
470  free(op->provider);
471 
472  free(op->stdout_data);
473  free(op->stderr_data);
474 
475  if (op->params) {
476  g_hash_table_destroy(op->params);
477  op->params = NULL;
478  }
479 
480  free(op);
481 }
482 
483 gboolean
485 {
486  crm_info("Cancelling %s operation %s", op->standard, op->id);
487 
488  if (recurring_actions) {
489  g_hash_table_remove(recurring_actions, op->id);
490  }
491 
492  if (op->opaque->repeat_timer) {
493  g_source_remove(op->opaque->repeat_timer);
494  op->opaque->repeat_timer = 0;
495  }
496 
497  return TRUE;
498 }
499 
509 gboolean
510 services_action_cancel(const char *name, const char *action, int interval)
511 {
512  gboolean cancelled = FALSE;
513  char *id = generate_op_key(name, action, interval);
514  svc_action_t *op = g_hash_table_lookup(recurring_actions, id);
515 
516  /* We can only cancel a recurring action */
517  if (op == NULL) {
518  goto done;
519  }
520 
521  /* Tell operation_finalize() not to reschedule the operation */
522  op->cancel = TRUE;
523 
524  /* Stop tracking it as a recurring operation, and stop its timer */
526 
527  /* If the op has a PID, it's an in-flight child process, so kill it.
528  *
529  * Whether the kill succeeds or fails, the main loop will send the op to
530  * operation_finished() (and thus operation_finalize()) when the process
531  * goes away.
532  */
533  if (op->pid != 0) {
534  crm_info("Terminating in-flight op %s (pid %d) early because it was cancelled",
535  id, op->pid);
536  cancelled = mainloop_child_kill(op->pid);
537  if (cancelled == FALSE) {
538  crm_err("Termination of %s (pid %d) failed", id, op->pid);
539  }
540  goto done;
541  }
542 
543  /* In-flight systemd and upstart ops don't have a pid. The relevant handlers
544  * will call operation_finalize() when the operation completes.
545  * @TODO: Can we request early termination, maybe using
546  * dbus_pending_call_cancel()?
547  */
548  if (inflight_systemd_or_upstart(op)) {
549  crm_info("Will cancel %s op %s when in-flight instance completes",
550  op->standard, op->id);
551  cancelled = FALSE;
552  goto done;
553  }
554 
555  /* Otherwise, operation is not in-flight, just report as cancelled */
557  if (op->opaque->callback) {
558  op->opaque->callback(op);
559  }
560 
561  blocked_ops = g_list_remove(blocked_ops, op);
563  cancelled = TRUE;
564 
565 done:
566  free(id);
567  return cancelled;
568 }
569 
570 gboolean
571 services_action_kick(const char *name, const char *action, int interval /* ms */)
572 {
573  svc_action_t * op = NULL;
574  char *id = NULL;
575 
576  if (asprintf(&id, "%s_%s_%d", name, action, interval) == -1) {
577  return FALSE;
578  }
579 
580  op = g_hash_table_lookup(recurring_actions, id);
581  free(id);
582 
583  if (op == NULL) {
584  return FALSE;
585  }
586 
587 
588  if (op->pid || inflight_systemd_or_upstart(op)) {
589  return TRUE;
590  } else {
591  if (op->opaque->repeat_timer) {
592  g_source_remove(op->opaque->repeat_timer);
593  op->opaque->repeat_timer = 0;
594  }
596  return TRUE;
597  }
598 
599 }
600 
601 /* add new recurring operation, check for duplicates.
602  * - if duplicate found, return TRUE, immediately reschedule op.
603  * - if no dup, return FALSE, inserve into recurring op list.*/
604 static gboolean
605 handle_duplicate_recurring(svc_action_t * op, void (*action_callback) (svc_action_t *))
606 {
607  svc_action_t * dup = NULL;
608 
609  if (recurring_actions == NULL) {
610  recurring_actions = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
611  return FALSE;
612  }
613 
614  /* check for duplicates */
615  dup = g_hash_table_lookup(recurring_actions, op->id);
616 
617  if (dup && (dup != op)) {
618  /* update user data */
619  if (op->opaque->callback) {
620  dup->opaque->callback = op->opaque->callback;
621  dup->cb_data = op->cb_data;
622  op->cb_data = NULL;
623  }
624  /* immediately execute the next interval */
625  if (dup->pid != 0) {
626  if (op->opaque->repeat_timer) {
627  g_source_remove(op->opaque->repeat_timer);
628  op->opaque->repeat_timer = 0;
629  }
631  }
632  /* free the dup. */
634  return TRUE;
635  }
636 
637  return FALSE;
638 }
639 
640 static gboolean
641 action_async_helper(svc_action_t * op)
642 {
643  if (op->standard && strcasecmp(op->standard, "upstart") == 0) {
644 #if SUPPORT_UPSTART
645  return upstart_job_exec(op, FALSE);
646 #endif
647  } else if (op->standard && strcasecmp(op->standard, "systemd") == 0) {
648 #if SUPPORT_SYSTEMD
649  return systemd_unit_exec(op);
650 #endif
651  } else {
652  return services_os_action_execute(op, FALSE);
653  }
654  /* The 'op' has probably been freed if the execution functions return TRUE. */
655  /* Avoid using the 'op' in here. */
656 
657  return FALSE;
658 }
659 
660 void
662 {
663  if (op == NULL) {
664  return;
665  }
666 
667  CRM_ASSERT(op->synchronous == FALSE);
668 
669  /* keep track of ops that are in-flight to avoid collisions in the same namespace */
670  if (op->rsc) {
671  inflight_ops = g_list_append(inflight_ops, op);
672  }
673 }
674 
681 void
683 {
684  /* Op is no longer in-flight or blocked */
685  inflight_ops = g_list_remove(inflight_ops, op);
686  blocked_ops = g_list_remove(blocked_ops, op);
687 
688  /* Op is no longer blocking other ops, so check if any need to run */
690 }
691 
692 gboolean
693 services_action_async(svc_action_t * op, void (*action_callback) (svc_action_t *))
694 {
695  op->synchronous = false;
696  if (action_callback) {
697  op->opaque->callback = action_callback;
698  }
699 
700  if (op->interval > 0) {
701  if (handle_duplicate_recurring(op, action_callback) == TRUE) {
702  /* entry rescheduled, dup freed */
703  /* exit early */
704  return TRUE;
705  }
706  g_hash_table_replace(recurring_actions, op->id, op);
707  }
708 
709  if (op->rsc && is_op_blocked(op->rsc)) {
710  blocked_ops = g_list_append(blocked_ops, op);
711  return TRUE;
712  }
713 
714  return action_async_helper(op);
715 }
716 
717 
718 static gboolean processing_blocked_ops = FALSE;
719 
720 gboolean
721 is_op_blocked(const char *rsc)
722 {
723  GList *gIter = NULL;
724  svc_action_t *op = NULL;
725 
726  for (gIter = inflight_ops; gIter != NULL; gIter = gIter->next) {
727  op = gIter->data;
728  if (safe_str_eq(op->rsc, rsc)) {
729  return TRUE;
730  }
731  }
732 
733  return FALSE;
734 }
735 
736 void
738 {
739  GList *executed_ops = NULL;
740  GList *gIter = NULL;
741  svc_action_t *op = NULL;
742  gboolean res = FALSE;
743 
744  if (processing_blocked_ops) {
745  /* avoid nested calling of this function */
746  return;
747  }
748 
749  processing_blocked_ops = TRUE;
750 
751  /* n^2 operation here, but blocked ops are incredibly rare. this list
752  * will be empty 99% of the time. */
753  for (gIter = blocked_ops; gIter != NULL; gIter = gIter->next) {
754  op = gIter->data;
755  if (is_op_blocked(op->rsc)) {
756  continue;
757  }
758  executed_ops = g_list_append(executed_ops, op);
759  res = action_async_helper(op);
760  if (res == FALSE) {
762  /* this can cause this function to be called recursively
763  * which is why we have processing_blocked_ops static variable */
764  operation_finalize(op);
765  }
766  }
767 
768  for (gIter = executed_ops; gIter != NULL; gIter = gIter->next) {
769  op = gIter->data;
770  blocked_ops = g_list_remove(blocked_ops, op);
771  }
772  g_list_free(executed_ops);
773 
774  processing_blocked_ops = FALSE;
775 }
776 
777 gboolean
779 {
780  gboolean rc = TRUE;
781 
782  if (op == NULL) {
783  crm_trace("No operation to execute");
784  return FALSE;
785  }
786 
787  op->synchronous = true;
788  if (op->standard && strcasecmp(op->standard, "upstart") == 0) {
789 #if SUPPORT_UPSTART
790  rc = upstart_job_exec(op, TRUE);
791 #endif
792  } else if (op->standard && strcasecmp(op->standard, "systemd") == 0) {
793 #if SUPPORT_SYSTEMD
794  rc = systemd_unit_exec(op);
795 #endif
796  } else {
797  rc = services_os_action_execute(op, TRUE);
798  }
799  crm_trace(" > %s_%s_%d: %s = %d", op->rsc, op->action, op->interval, op->opaque->exec, op->rc);
800  if (op->stdout_data) {
801  crm_trace(" > stdout: %s", op->stdout_data);
802  }
803  if (op->stderr_data) {
804  crm_trace(" > stderr: %s", op->stderr_data);
805  }
806  return rc;
807 }
808 
809 GList *
810 get_directory_list(const char *root, gboolean files, gboolean executable)
811 {
812  return services_os_get_directory_list(root, files, executable);
813 }
814 
815 GList *
817 {
818  return resources_list_agents("lsb", NULL);
819 }
820 
821 #if SUPPORT_HEARTBEAT
822 static GList *
823 resources_os_list_hb_agents(void)
824 {
825  return services_os_get_directory_list(HB_RA_DIR, TRUE, TRUE);
826 }
827 #endif
828 
829 GList *
831 {
832  GList *standards = NULL;
833  GList *agents = NULL;
834 
835  standards = g_list_append(standards, strdup("ocf"));
836  standards = g_list_append(standards, strdup("lsb"));
837  standards = g_list_append(standards, strdup("service"));
838 
839 #if SUPPORT_SYSTEMD
840  agents = systemd_unit_listall();
841 #else
842  agents = NULL;
843 #endif
844 
845  if (agents) {
846  standards = g_list_append(standards, strdup("systemd"));
847  g_list_free_full(agents, free);
848  }
849 #if SUPPORT_UPSTART
850  agents = upstart_job_listall();
851 #else
852  agents = NULL;
853 #endif
854 
855  if (agents) {
856  standards = g_list_append(standards, strdup("upstart"));
857  g_list_free_full(agents, free);
858  }
859 #if SUPPORT_NAGIOS
861  if (agents) {
862  standards = g_list_append(standards, strdup("nagios"));
863  g_list_free_full(agents, free);
864  }
865 #endif
866 
867 #if SUPPORT_HEARTBEAT
868  standards = g_list_append(standards, strdup("heartbeat"));
869 #endif
870 
871  return standards;
872 }
873 
874 GList *
875 resources_list_providers(const char *standard)
876 {
877  if (strcasecmp(standard, "ocf") == 0) {
879  }
880 
881  return NULL;
882 }
883 
884 GList *
885 resources_list_agents(const char *standard, const char *provider)
886 {
887  if (standard == NULL || strcasecmp(standard, "service") == 0) {
888  GList *tmp1;
889  GList *tmp2;
890  GList *result = resources_os_list_lsb_agents();
891 
892  if (standard == NULL) {
893  tmp1 = result;
894  tmp2 = resources_os_list_ocf_agents(NULL);
895  if (tmp2) {
896  result = g_list_concat(tmp1, tmp2);
897  }
898  }
899 #if SUPPORT_SYSTEMD
900  tmp1 = result;
901  tmp2 = systemd_unit_listall();
902  if (tmp2) {
903  result = g_list_concat(tmp1, tmp2);
904  }
905 #endif
906 
907 #if SUPPORT_UPSTART
908  tmp1 = result;
909  tmp2 = upstart_job_listall();
910  if (tmp2) {
911  result = g_list_concat(tmp1, tmp2);
912  }
913 #endif
914 
915  return result;
916 
917  } else if (strcasecmp(standard, "ocf") == 0) {
918  return resources_os_list_ocf_agents(provider);
919  } else if (strcasecmp(standard, "lsb") == 0) {
921 #if SUPPORT_HEARTBEAT
922  } else if (strcasecmp(standard, "heartbeat") == 0) {
923  return resources_os_list_hb_agents();
924 #endif
925 #if SUPPORT_SYSTEMD
926  } else if (strcasecmp(standard, "systemd") == 0) {
927  return systemd_unit_listall();
928 #endif
929 #if SUPPORT_UPSTART
930  } else if (strcasecmp(standard, "upstart") == 0) {
931  return upstart_job_listall();
932 #endif
933 #if SUPPORT_NAGIOS
934  } else if (strcasecmp(standard, "nagios") == 0) {
936 #endif
937  }
938 
939  return NULL;
940 }
gboolean services_action_cancel(const char *name, const char *action, int interval)
Cancel a recurring action.
Definition: services.c:510
Services API.
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:164
void(* callback)(svc_action_t *op)
A dumping ground.
GList * resources_list_providers(const char *standard)
Get a list of providers.
Definition: services.c:875
char * standard
Definition: services.h:157
#define SERVICE_SCRIPT
Definition: services.h:51
gboolean upstart_job_exists(const char *name)
Definition: upstart.c:247
gboolean mainloop_child_kill(pid_t pid)
Definition: mainloop.c:1038
char * id
Definition: services.h:152
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:118
mainloop_io_t * stderr_gsource
GList * resources_os_list_ocf_agents(const char *provider)
GList * resources_os_list_ocf_providers(void)
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:693
char * rsc
Definition: services.h:153
int interval
Definition: services.h:155
svc_action_flags
Definition: services.h:143
gboolean is_op_blocked(const char *rsc)
Definition: services.c:721
Wrappers for and extensions to glib mainloop.
svc_action_t * services_action_create_generic(const char *exec, const char *args[])
Definition: services.c:344
GList * resources_os_list_lsb_agents(void)
GList * blocked_ops
Definition: services.c:55
gboolean upstart_job_exec(svc_action_t *op, gboolean synchronous)
Definition: upstart.c:432
enum svc_action_flags flags
Definition: services.h:171
gboolean services_os_action_execute(svc_action_t *op, gboolean synchronous)
#define crm_warn(fmt, args...)
Definition: logging.h:249
GList * services_list(void)
Definition: services.c:816
gboolean cancel_recurring_action(svc_action_t *op)
Definition: services.c:484
svc_action_private_t * opaque
Definition: services.h:184
GList * upstart_job_listall(void)
Definition: upstart.c:167
uint64_t flags
Definition: remote.c:121
#define OCF_ROOT_DIR
Definition: services.h:38
#define crm_debug(fmt, args...)
Definition: logging.h:253
gboolean operation_finalize(svc_action_t *op)
char * stdout_data
Definition: services.h:174
gboolean systemd_unit_exists(const char *name)
Definition: systemd.c:383
GHashTable * params
Definition: services.h:162
#define crm_trace(fmt, args...)
Definition: logging.h:254
char * agent
Definition: services.h:159
GList * inflight_ops
Definition: services.c:58
int synchronous
Definition: services.h:170
gboolean services_action_sync(svc_action_t *op)
Definition: services.c:778
#define SUPPORT_HEARTBEAT
Definition: config.h:604
#define LSB_ROOT_DIR
Definition: services.h:42
int sequence
Definition: services.h:168
gboolean services_action_kick(const char *name, const char *action, int interval)
Definition: services.c:571
GList * systemd_unit_listall(void)
Definition: systemd.c:299
const char * resources_find_service_class(const char *agent)
Definition: services.c:67
GList * resources_list_agents(const char *standard, const char *provider)
Get a list of resource agents.
Definition: services.c:885
#define MAX_ARGC
char * args[MAX_ARGC]
void services_add_inflight_op(svc_action_t *op)
Definition: services.c:661
GList * resources_list_standards(void)
Definition: services.c:830
void services_untrack_op(svc_action_t *op)
Definition: services.c:682
char * action
Definition: services.h:154
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:810
#define NAGIOS_PLUGIN_DIR
Definition: config.h:502
#define CRM_META
Definition: crm.h:55
#define crm_err(fmt, args...)
Definition: logging.h:248
GList * resources_os_list_nagios_agents(void)
#define DIMOF(a)
Definition: crm.h:41
GHashTable * recurring_actions
Definition: services.c:51
mainloop_io_t * stdout_gsource
#define CRM_ASSERT(expr)
Definition: error.h:35
#define XML_ATTR_CRM_VERSION
Definition: msg_xml.h:83
void mainloop_del_fd(mainloop_io_t *client)
Definition: mainloop.c:850
void * cb_data
Definition: services.h:182
void services_action_cleanup(svc_action_t *op)
Definition: services.c:396
char * generate_op_key(const char *rsc_id, const char *op_type, int interval)
Definition: utils.c:794
#define safe_str_eq(a, b)
Definition: util.h:74
void handle_blocked_ops(void)
Definition: services.c:737
void services_action_free(svc_action_t *op)
Definition: services.c:432
char * provider
Definition: services.h:158
gboolean systemd_unit_exec(svc_action_t *op)
Definition: systemd.c:666
#define crm_info(fmt, args...)
Definition: logging.h:251
svc_action_t * services_action_create(const char *name, const char *action, int interval, int timeout)
Definition: services.c:61
char * stderr_data
Definition: services.h:173