pacemaker  1.1.14-70404b0
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
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 
101 
102 svc_action_t *
103 resources_action_create(const char *name, const char *standard, const char *provider,
104  const char *agent, const char *action, int interval, int timeout,
105  GHashTable * params, enum svc_action_flags flags)
106 {
107  svc_action_t *op = NULL;
108 
109  /*
110  * Do some up front sanity checks before we go off and
111  * build the svc_action_t instance.
112  */
113 
114  if (crm_strlen_zero(name)) {
115  crm_err("A service or resource action must have a name.");
116  goto return_error;
117  }
118 
119  if (crm_strlen_zero(standard)) {
120  crm_err("A service action must have a valid standard.");
121  goto return_error;
122  }
123 
124  if (!strcasecmp(standard, "ocf") && crm_strlen_zero(provider)) {
125  crm_err("An OCF resource action must have a provider.");
126  goto return_error;
127  }
128 
129  if (crm_strlen_zero(agent)) {
130  crm_err("A service or resource action must have an agent.");
131  goto return_error;
132  }
133 
134  if (crm_strlen_zero(action)) {
135  crm_err("A service or resource action must specify an action.");
136  goto return_error;
137  }
138 
139  if (safe_str_eq(action, "monitor") && (
141  safe_str_eq(standard, "heartbeat") ||
142 #endif
143  safe_str_eq(standard, "lsb") || safe_str_eq(standard, "service"))) {
144  action = "status";
145  }
146 
147  /*
148  * Sanity checks passed, proceed!
149  */
150 
151  op = calloc(1, sizeof(svc_action_t));
152  op->opaque = calloc(1, sizeof(svc_action_private_t));
153  op->rsc = strdup(name);
154  op->action = strdup(action);
155  op->interval = interval;
156  op->timeout = timeout;
157  op->standard = strdup(standard);
158  op->agent = strdup(agent);
159  op->sequence = ++operations;
160  op->flags = flags;
161 
162  if (asprintf(&op->id, "%s_%s_%d", name, action, interval) == -1) {
163  goto return_error;
164  }
165 
166  if (strcasecmp(op->standard, "service") == 0) {
167  const char *expanded = resources_find_service_class(op->agent);
168 
169  if(expanded) {
170  crm_debug("Found a %s agent for %s/%s", expanded, op->rsc, op->agent);
171  free(op->standard);
172  op->standard = strdup(expanded);
173 
174  } else {
175  crm_info("Cannot determine the standard for %s (%s)", op->rsc, op->agent);
176  free(op->standard);
177  op->standard = strdup("lsb");
178  }
179  CRM_ASSERT(op->standard);
180  }
181 
182  if (strcasecmp(op->standard, "ocf") == 0) {
183  op->provider = strdup(provider);
184  op->params = params;
185  params = NULL;
186 
187  if (asprintf(&op->opaque->exec, "%s/resource.d/%s/%s", OCF_ROOT_DIR, provider, agent) == -1) {
188  crm_err("Internal error: cannot create agent path");
189  goto return_error;
190  }
191  op->opaque->args[0] = strdup(op->opaque->exec);
192  op->opaque->args[1] = strdup(action);
193 
194  } else if (strcasecmp(op->standard, "lsb") == 0) {
195  if (op->agent[0] == '/') {
196  /* if given an absolute path, use that instead
197  * of tacking on the LSB_ROOT_DIR path to the front */
198  op->opaque->exec = strdup(op->agent);
199  } else if (asprintf(&op->opaque->exec, "%s/%s", LSB_ROOT_DIR, op->agent) == -1) {
200  crm_err("Internal error: cannot create agent path");
201  goto return_error;
202  }
203  op->opaque->args[0] = strdup(op->opaque->exec);
204  op->opaque->args[1] = strdup(op->action);
205  op->opaque->args[2] = NULL;
206 #if SUPPORT_HEARTBEAT
207  } else if (strcasecmp(op->standard, "heartbeat") == 0) {
208  int index;
209  int param_num;
210  char buf_tmp[20];
211  void *value_tmp;
212 
213  if (op->agent[0] == '/') {
214  /* if given an absolute path, use that instead
215  * of tacking on the HB_RA_DIR path to the front */
216  op->opaque->exec = strdup(op->agent);
217  } else if (asprintf(&op->opaque->exec, "%s/%s", HB_RA_DIR, op->agent) == -1) {
218  crm_err("Internal error: cannot create agent path");
219  goto return_error;
220  }
221  op->opaque->args[0] = strdup(op->opaque->exec);
222 
223  /* The "heartbeat" agent class only has positional arguments,
224  * which we keyed by their decimal position number. */
225  param_num = 1;
226  for (index = 1; index <= MAX_ARGC - 3; index++ ) {
227  snprintf(buf_tmp, sizeof(buf_tmp), "%d", index);
228  value_tmp = g_hash_table_lookup(params, buf_tmp);
229  if (value_tmp == NULL) {
230  /* maybe: strdup("") ??
231  * But the old lrmd did simply continue as well. */
232  continue;
233  }
234  op->opaque->args[param_num++] = strdup(value_tmp);
235  }
236 
237  /* Add operation code as the last argument, */
238  /* and the teminating NULL pointer */
239  op->opaque->args[param_num++] = strdup(op->action);
240  op->opaque->args[param_num] = NULL;
241 #endif
242 #if SUPPORT_SYSTEMD
243  } else if (strcasecmp(op->standard, "systemd") == 0) {
244  op->opaque->exec = strdup("systemd-dbus");
245 #endif
246 #if SUPPORT_UPSTART
247  } else if (strcasecmp(op->standard, "upstart") == 0) {
248  op->opaque->exec = strdup("upstart-dbus");
249 #endif
250  } else if (strcasecmp(op->standard, "service") == 0) {
251  op->opaque->exec = strdup(SERVICE_SCRIPT);
252  op->opaque->args[0] = strdup(SERVICE_SCRIPT);
253  op->opaque->args[1] = strdup(agent);
254  op->opaque->args[2] = strdup(action);
255 
256 #if SUPPORT_NAGIOS
257  } else if (strcasecmp(op->standard, "nagios") == 0) {
258  int index = 0;
259 
260  if (op->agent[0] == '/') {
261  /* if given an absolute path, use that instead
262  * of tacking on the NAGIOS_PLUGIN_DIR path to the front */
263  op->opaque->exec = strdup(op->agent);
264 
265  } else if (asprintf(&op->opaque->exec, "%s/%s", NAGIOS_PLUGIN_DIR, op->agent) == -1) {
266  crm_err("Internal error: cannot create agent path");
267  goto return_error;
268  }
269 
270  op->opaque->args[0] = strdup(op->opaque->exec);
271  index = 1;
272 
273  if (safe_str_eq(op->action, "monitor") && op->interval == 0) {
274  /* Invoke --version for a nagios probe */
275  op->opaque->args[index] = strdup("--version");
276  index++;
277 
278  } else if (params) {
279  GHashTableIter iter;
280  char *key = NULL;
281  char *value = NULL;
282  static int args_size = sizeof(op->opaque->args) / sizeof(char *);
283 
284  g_hash_table_iter_init(&iter, params);
285 
286  while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value) &&
287  index <= args_size - 3) {
288  int len = 3;
289  char *long_opt = NULL;
290 
291  if (safe_str_eq(key, XML_ATTR_CRM_VERSION) || strstr(key, CRM_META "_")) {
292  continue;
293  }
294 
295  len += strlen(key);
296  long_opt = calloc(1, len);
297  sprintf(long_opt, "--%s", key);
298  long_opt[len - 1] = 0;
299 
300  op->opaque->args[index] = long_opt;
301  op->opaque->args[index + 1] = strdup(value);
302  index += 2;
303  }
304  }
305  op->opaque->args[index] = NULL;
306 #endif
307 
308  } else {
309  crm_err("Unknown resource standard: %s", op->standard);
311  op = NULL;
312  }
313 
314  if(params) {
315  g_hash_table_destroy(params);
316  }
317  return op;
318 
319  return_error:
320  if(params) {
321  g_hash_table_destroy(params);
322  }
324 
325  return NULL;
326 }
327 
328 svc_action_t *
329 services_action_create_generic(const char *exec, const char *args[])
330 {
331  svc_action_t *op;
332  unsigned int cur_arg;
333 
334  op = calloc(1, sizeof(*op));
335  op->opaque = calloc(1, sizeof(svc_action_private_t));
336 
337  op->opaque->exec = strdup(exec);
338  op->opaque->args[0] = strdup(exec);
339 
340  for (cur_arg = 1; args && args[cur_arg - 1]; cur_arg++) {
341  op->opaque->args[cur_arg] = strdup(args[cur_arg - 1]);
342 
343  if (cur_arg == DIMOF(op->opaque->args) - 1) {
344  crm_err("svc_action_t args list not long enough for '%s' execution request.", exec);
345  break;
346  }
347  }
348 
349  return op;
350 }
351 
352 #if SUPPORT_DBUS
353 /*
354  * \internal
355  * \brief Update operation's pending DBus call, unreferencing old one if needed
356  *
357  * \param[in,out] op Operation to modify
358  * \param[in] pending Pending call to set
359  */
360 void
361 services_set_op_pending(svc_action_t *op, DBusPendingCall *pending)
362 {
363  if (op->opaque->pending && (op->opaque->pending != pending)) {
364  if (pending) {
365  crm_info("Lost pending %s DBus call (%p)", op->id, op->opaque->pending);
366  } else {
367  crm_trace("Done with pending %s DBus call (%p)", op->id, op->opaque->pending);
368  }
369  dbus_pending_call_unref(op->opaque->pending);
370  }
371  op->opaque->pending = pending;
372  if (pending) {
373  crm_trace("Updated pending %s DBus call (%p)", op->id, pending);
374  } else {
375  crm_trace("Cleared pending %s DBus call", op->id);
376  }
377 }
378 #endif
379 
380 void
382 {
383 #if SUPPORT_DBUS
384  if(op->opaque == NULL) {
385  return;
386  }
387 
388  if(op->opaque->timerid != 0) {
389  crm_trace("Removing timer for call %s to %s", op->action, op->rsc);
390  g_source_remove(op->opaque->timerid);
391  op->opaque->timerid = 0;
392  }
393 
394  if(op->opaque->pending) {
395  crm_trace("Cleaning up pending dbus call %p %s for %s", op->opaque->pending, op->action, op->rsc);
396  if(dbus_pending_call_get_completed(op->opaque->pending)) {
397  crm_warn("Pending dbus call %s for %s did not complete", op->action, op->rsc);
398  }
399  dbus_pending_call_cancel(op->opaque->pending);
400  dbus_pending_call_unref(op->opaque->pending);
401  op->opaque->pending = NULL;
402  }
403 
404  if (op->opaque->stderr_gsource) {
406  op->opaque->stderr_gsource = NULL;
407  }
408 
409  if (op->opaque->stdout_gsource) {
411  op->opaque->stdout_gsource = NULL;
412  }
413 #endif
414 }
415 
416 void
418 {
419  unsigned int i;
420 
421  if (op == NULL) {
422  return;
423  }
424 
426 
427  if (op->opaque->repeat_timer) {
428  g_source_remove(op->opaque->repeat_timer);
429  op->opaque->repeat_timer = 0;
430  }
431 
432  free(op->id);
433  free(op->opaque->exec);
434 
435  for (i = 0; i < DIMOF(op->opaque->args); i++) {
436  free(op->opaque->args[i]);
437  }
438 
439  free(op->opaque);
440  free(op->rsc);
441  free(op->action);
442 
443  free(op->standard);
444  free(op->agent);
445  free(op->provider);
446 
447  free(op->stdout_data);
448  free(op->stderr_data);
449 
450  if (op->params) {
451  g_hash_table_destroy(op->params);
452  op->params = NULL;
453  }
454 
455  free(op);
456 }
457 
458 gboolean
460 {
461  crm_info("Cancelling %s operation %s", op->standard, op->id);
462 
463  if (recurring_actions) {
464  g_hash_table_remove(recurring_actions, op->id);
465  }
466 
467  if (op->opaque->repeat_timer) {
468  g_source_remove(op->opaque->repeat_timer);
469  op->opaque->repeat_timer = 0;
470  }
471 
472  return TRUE;
473 }
474 
475 gboolean
476 services_action_cancel(const char *name, const char *action, int interval)
477 {
478  svc_action_t *op = NULL;
479  char id[512];
480 
481  snprintf(id, sizeof(id), "%s_%s_%d", name, action, interval);
482 
483  if (!(op = g_hash_table_lookup(recurring_actions, id))) {
484  return FALSE;
485  }
486 
487  /* Always kill the recurring timer */
489 
490  if (op->pid == 0) {
492  if (op->opaque->callback) {
493  op->opaque->callback(op);
494  }
495 
496  blocked_ops = g_list_remove(blocked_ops, op);
498 
499  } else {
500  crm_info("Cancelling in-flight op: performing early termination of %s (pid=%d)", id, op->pid);
501  op->cancel = 1;
502  if (mainloop_child_kill(op->pid) == FALSE) {
503  /* even though the early termination failed,
504  * the op will be marked as cancelled once it completes. */
505  crm_err("Termination of %s (pid=%d) failed", id, op->pid);
506  return FALSE;
507  }
508  }
509 
510  return TRUE;
511 }
512 
513 gboolean
514 services_action_kick(const char *name, const char *action, int interval /* ms */)
515 {
516  svc_action_t * op = NULL;
517  char *id = NULL;
518 
519  if (asprintf(&id, "%s_%s_%d", name, action, interval) == -1) {
520  return FALSE;
521  }
522 
523  op = g_hash_table_lookup(recurring_actions, id);
524  free(id);
525 
526  if (op == NULL) {
527  return FALSE;
528  }
529 
530  if (op->pid) {
531  return TRUE;
532  } else {
533  if (op->opaque->repeat_timer) {
534  g_source_remove(op->opaque->repeat_timer);
535  op->opaque->repeat_timer = 0;
536  }
538  return TRUE;
539  }
540 
541 }
542 
543 /* add new recurring operation, check for duplicates.
544  * - if duplicate found, return TRUE, immediately reschedule op.
545  * - if no dup, return FALSE, inserve into recurring op list.*/
546 static gboolean
547 handle_duplicate_recurring(svc_action_t * op, void (*action_callback) (svc_action_t *))
548 {
549  svc_action_t * dup = NULL;
550 
551  if (recurring_actions == NULL) {
552  recurring_actions = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
553  return FALSE;
554  }
555 
556  /* check for duplicates */
557  dup = g_hash_table_lookup(recurring_actions, op->id);
558 
559  if (dup && (dup != op)) {
560  /* update user data */
561  if (op->opaque->callback) {
562  dup->opaque->callback = op->opaque->callback;
563  dup->cb_data = op->cb_data;
564  op->cb_data = NULL;
565  }
566  /* immediately execute the next interval */
567  if (dup->pid != 0) {
568  if (op->opaque->repeat_timer) {
569  g_source_remove(op->opaque->repeat_timer);
570  op->opaque->repeat_timer = 0;
571  }
573  }
574  /* free the dup. */
576  return TRUE;
577  }
578 
579  return FALSE;
580 }
581 
582 static gboolean
583 action_async_helper(svc_action_t * op)
584 {
585  if (op->standard && strcasecmp(op->standard, "upstart") == 0) {
586 #if SUPPORT_UPSTART
587  return upstart_job_exec(op, FALSE);
588 #endif
589  } else if (op->standard && strcasecmp(op->standard, "systemd") == 0) {
590 #if SUPPORT_SYSTEMD
591  return systemd_unit_exec(op);
592 #endif
593  } else {
594  return services_os_action_execute(op, FALSE);
595  }
596  /* The 'op' has probably been freed if the execution functions return TRUE. */
597  /* Avoid using the 'op' in here. */
598 
599  return FALSE;
600 }
601 
602 void
604 {
605  if (op == NULL) {
606  return;
607  }
608 
609  CRM_ASSERT(op->synchronous == FALSE);
610 
611  /* keep track of ops that are in-flight to avoid collisions in the same namespace */
612  if (op->rsc) {
613  inflight_ops = g_list_append(inflight_ops, op);
614  }
615 }
616 
617 gboolean
618 services_action_async(svc_action_t * op, void (*action_callback) (svc_action_t *))
619 {
620  op->synchronous = false;
621  if (action_callback) {
622  op->opaque->callback = action_callback;
623  }
624 
625  if (op->interval > 0) {
626  if (handle_duplicate_recurring(op, action_callback) == TRUE) {
627  /* entry rescheduled, dup freed */
628  /* exit early */
629  return TRUE;
630  }
631  g_hash_table_replace(recurring_actions, op->id, op);
632  }
633 
634  if (op->rsc && is_op_blocked(op->rsc)) {
635  blocked_ops = g_list_append(blocked_ops, op);
636  return TRUE;
637  }
638 
639  return action_async_helper(op);
640 }
641 
642 
643 static gboolean processing_blocked_ops = FALSE;
644 
645 gboolean
646 is_op_blocked(const char *rsc)
647 {
648  GList *gIter = NULL;
649  svc_action_t *op = NULL;
650 
651  for (gIter = inflight_ops; gIter != NULL; gIter = gIter->next) {
652  op = gIter->data;
653  if (safe_str_eq(op->rsc, rsc)) {
654  return TRUE;
655  }
656  }
657 
658  return FALSE;
659 }
660 
661 void
663 {
664  GList *executed_ops = NULL;
665  GList *gIter = NULL;
666  svc_action_t *op = NULL;
667  gboolean res = FALSE;
668 
669  if (processing_blocked_ops) {
670  /* avoid nested calling of this function */
671  return;
672  }
673 
674  processing_blocked_ops = TRUE;
675 
676  /* n^2 operation here, but blocked ops are incredibly rare. this list
677  * will be empty 99% of the time. */
678  for (gIter = blocked_ops; gIter != NULL; gIter = gIter->next) {
679  op = gIter->data;
680  if (is_op_blocked(op->rsc)) {
681  continue;
682  }
683  executed_ops = g_list_append(executed_ops, op);
684  res = action_async_helper(op);
685  if (res == FALSE) {
687  /* this can cause this function to be called recursively
688  * which is why we have processing_blocked_ops static variable */
689  operation_finalize(op);
690  }
691  }
692 
693  for (gIter = executed_ops; gIter != NULL; gIter = gIter->next) {
694  op = gIter->data;
695  blocked_ops = g_list_remove(blocked_ops, op);
696  }
697  g_list_free(executed_ops);
698 
699  processing_blocked_ops = FALSE;
700 }
701 
702 gboolean
704 {
705  gboolean rc = TRUE;
706 
707  if (op == NULL) {
708  crm_trace("No operation to execute");
709  return FALSE;
710  }
711 
712  op->synchronous = true;
713  if (op->standard && strcasecmp(op->standard, "upstart") == 0) {
714 #if SUPPORT_UPSTART
715  rc = upstart_job_exec(op, TRUE);
716 #endif
717  } else if (op->standard && strcasecmp(op->standard, "systemd") == 0) {
718 #if SUPPORT_SYSTEMD
719  rc = systemd_unit_exec(op);
720 #endif
721  } else {
722  rc = services_os_action_execute(op, TRUE);
723  }
724  crm_trace(" > %s_%s_%d: %s = %d", op->rsc, op->action, op->interval, op->opaque->exec, op->rc);
725  if (op->stdout_data) {
726  crm_trace(" > stdout: %s", op->stdout_data);
727  }
728  if (op->stderr_data) {
729  crm_trace(" > stderr: %s", op->stderr_data);
730  }
731  return rc;
732 }
733 
734 GList *
735 get_directory_list(const char *root, gboolean files, gboolean executable)
736 {
737  return services_os_get_directory_list(root, files, executable);
738 }
739 
740 GList *
742 {
743  return resources_list_agents("lsb", NULL);
744 }
745 
746 #if SUPPORT_HEARTBEAT
747 static GList *
748 resources_os_list_hb_agents(void)
749 {
750  return services_os_get_directory_list(HB_RA_DIR, TRUE, TRUE);
751 }
752 #endif
753 
754 GList *
756 {
757  GList *standards = NULL;
758  GList *agents = NULL;
759 
760  standards = g_list_append(standards, strdup("ocf"));
761  standards = g_list_append(standards, strdup("lsb"));
762  standards = g_list_append(standards, strdup("service"));
763 
764 #if SUPPORT_SYSTEMD
765  agents = systemd_unit_listall();
766 #else
767  agents = NULL;
768 #endif
769 
770  if (agents) {
771  standards = g_list_append(standards, strdup("systemd"));
772  g_list_free_full(agents, free);
773  }
774 #if SUPPORT_UPSTART
775  agents = upstart_job_listall();
776 #else
777  agents = NULL;
778 #endif
779 
780  if (agents) {
781  standards = g_list_append(standards, strdup("upstart"));
782  g_list_free_full(agents, free);
783  }
784 #if SUPPORT_NAGIOS
786  if (agents) {
787  standards = g_list_append(standards, strdup("nagios"));
788  g_list_free_full(agents, free);
789  }
790 #endif
791 
792 #if SUPPORT_HEARTBEAT
793  standards = g_list_append(standards, strdup("heartbeat"));
794 #endif
795 
796  return standards;
797 }
798 
799 GList *
800 resources_list_providers(const char *standard)
801 {
802  if (strcasecmp(standard, "ocf") == 0) {
804  }
805 
806  return NULL;
807 }
808 
809 GList *
810 resources_list_agents(const char *standard, const char *provider)
811 {
812  if (standard == NULL || strcasecmp(standard, "service") == 0) {
813  GList *tmp1;
814  GList *tmp2;
815  GList *result = resources_os_list_lsb_agents();
816 
817  if (standard == NULL) {
818  tmp1 = result;
819  tmp2 = resources_os_list_ocf_agents(NULL);
820  if (tmp2) {
821  result = g_list_concat(tmp1, tmp2);
822  }
823  }
824 #if SUPPORT_SYSTEMD
825  tmp1 = result;
826  tmp2 = systemd_unit_listall();
827  if (tmp2) {
828  result = g_list_concat(tmp1, tmp2);
829  }
830 #endif
831 
832 #if SUPPORT_UPSTART
833  tmp1 = result;
834  tmp2 = upstart_job_listall();
835  if (tmp2) {
836  result = g_list_concat(tmp1, tmp2);
837  }
838 #endif
839 
840  return result;
841 
842  } else if (strcasecmp(standard, "ocf") == 0) {
843  return resources_os_list_ocf_agents(provider);
844  } else if (strcasecmp(standard, "lsb") == 0) {
846 #if SUPPORT_HEARTBEAT
847  } else if (strcasecmp(standard, "heartbeat") == 0) {
848  return resources_os_list_hb_agents();
849 #endif
850 #if SUPPORT_SYSTEMD
851  } else if (strcasecmp(standard, "systemd") == 0) {
852  return systemd_unit_listall();
853 #endif
854 #if SUPPORT_UPSTART
855  } else if (strcasecmp(standard, "upstart") == 0) {
856  return upstart_job_listall();
857 #endif
858 #if SUPPORT_NAGIOS
859  } else if (strcasecmp(standard, "nagios") == 0) {
861 #endif
862  }
863 
864  return NULL;
865 }
gboolean services_action_cancel(const char *name, const char *action, int interval)
Definition: services.c:476
Services API.
A dumping ground.
GList * resources_list_providers(const char *standard)
Get a list of providers.
Definition: services.c:800
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:103
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:618
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:646
Wrappers for and extensions to glib mainloop.
svc_action_t * services_action_create_generic(const char *exec, const char *args[])
Definition: services.c:329
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:741
gboolean cancel_recurring_action(svc_action_t *op)
Definition: services.c:459
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
void(* callback)(svc_action_t *op)
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:703
#define SUPPORT_HEARTBEAT
Definition: config.h:605
#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:514
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:810
#define MAX_ARGC
char * args[MAX_ARGC]
void services_add_inflight_op(svc_action_t *op)
Definition: services.c:603
GList * resources_list_standards(void)
Definition: services.c:755
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:735
#define NAGIOS_PLUGIN_DIR
Definition: config.h:503
#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:381
#define safe_str_eq(a, b)
Definition: util.h:74
void handle_blocked_ops(void)
Definition: services.c:662
void services_action_free(svc_action_t *op)
Definition: services.c:417
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