pacemaker  2.0.1-15814c6c0d
Scalable High-Availability cluster resource manager
services.c
Go to the documentation of this file.
1 /*
2  * Copyright 2010-2018 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 <stdio.h>
16 #include <errno.h>
17 #include <unistd.h>
18 #include <dirent.h>
19 #include <fcntl.h>
20 
21 #include <crm/crm.h>
22 #include <crm/common/mainloop.h>
23 #include <crm/services.h>
24 #include <crm/msg_xml.h>
25 #include "services_private.h"
26 #include "services_lsb.h"
27 
28 #if SUPPORT_UPSTART
29 # include <upstart.h>
30 #endif
31 
32 #if SUPPORT_SYSTEMD
33 # include <systemd.h>
34 #endif
35 
36 /* TODO: Develop a rollover strategy */
37 
38 static int operations = 0;
39 static GHashTable *recurring_actions = NULL;
40 
41 /* ops waiting to run async because of conflicting active
42  * pending ops */
43 static GList *blocked_ops = NULL;
44 
45 /* ops currently active (in-flight) */
46 static GList *inflight_ops = NULL;
47 
48 static void handle_blocked_ops(void);
49 
61 const char *
62 resources_find_service_class(const char *agent)
63 {
64  if (services__lsb_agent_exists(agent)) {
66  }
67 
68 #if SUPPORT_SYSTEMD
69  if (systemd_unit_exists(agent)) {
71  }
72 #endif
73 
74 #if SUPPORT_UPSTART
75  if (upstart_job_exists(agent)) {
77  }
78 #endif
79  return NULL;
80 }
81 
82 static inline void
83 init_recurring_actions(void)
84 {
85  if (recurring_actions == NULL) {
86  recurring_actions = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
87  NULL);
88  }
89 }
90 
99 static inline gboolean
100 inflight_systemd_or_upstart(svc_action_t *op)
101 {
104  && (g_list_find(inflight_ops, op) != NULL);
105 }
106 
119 static char *
120 expand_resource_class(const char *rsc, const char *standard, const char *agent)
121 {
122  char *expanded_class = NULL;
123 
124  if (strcasecmp(standard, PCMK_RESOURCE_CLASS_SERVICE) == 0) {
125  const char *found_class = resources_find_service_class(agent);
126 
127  if (found_class) {
128  crm_debug("Found %s agent %s for %s", found_class, agent, rsc);
129  expanded_class = strdup(found_class);
130  } else {
131  crm_info("Assuming resource class lsb for agent %s for %s",
132  agent, rsc);
133  expanded_class = strdup(PCMK_RESOURCE_CLASS_LSB);
134  }
135  } else {
136  expanded_class = strdup(standard);
137  }
138  CRM_ASSERT(expanded_class);
139  return expanded_class;
140 }
141 
150 static char *
151 dup_file_path(const char *filename, const char *dirname)
152 {
153  return (*filename == '/')? strdup(filename)
154  : crm_strdup_printf("%s/%s", dirname, filename);
155 }
156 
157 svc_action_t *
158 resources_action_create(const char *name, const char *standard,
159  const char *provider, const char *agent,
160  const char *action, guint interval_ms, int timeout,
161  GHashTable *params, enum svc_action_flags flags)
162 {
163  svc_action_t *op = NULL;
164  uint32_t ra_caps = 0;
165 
166  /*
167  * Do some up front sanity checks before we go off and
168  * build the svc_action_t instance.
169  */
170 
171  if (crm_strlen_zero(name)) {
172  crm_err("Cannot create operation without resource name");
173  goto return_error;
174  }
175 
176  if (crm_strlen_zero(standard)) {
177  crm_err("Cannot create operation for %s without resource class", name);
178  goto return_error;
179  }
180  ra_caps = pcmk_get_ra_caps(standard);
181 
182  if (is_set(ra_caps, pcmk_ra_cap_provider) && crm_strlen_zero(provider)) {
183  crm_err("Cannot create operation for %s without provider", name);
184  goto return_error;
185  }
186 
187  if (crm_strlen_zero(agent)) {
188  crm_err("Cannot create operation for %s without agent name", name);
189  goto return_error;
190  }
191 
192  if (crm_strlen_zero(action)) {
193  crm_err("Cannot create operation for %s without operation name", name);
194  goto return_error;
195  }
196 
197  /*
198  * Sanity checks passed, proceed!
199  */
200 
201  op = calloc(1, sizeof(svc_action_t));
202  op->opaque = calloc(1, sizeof(svc_action_private_t));
203  op->rsc = strdup(name);
204  op->interval_ms = interval_ms;
205  op->timeout = timeout;
206  op->standard = expand_resource_class(name, standard, agent);
207  op->agent = strdup(agent);
208  op->sequence = ++operations;
209  op->flags = flags;
210  op->id = generate_op_key(name, action, interval_ms);
211 
212  if (is_set(ra_caps, pcmk_ra_cap_status) && safe_str_eq(action, "monitor")) {
213  op->action = strdup("status");
214  } else {
215  op->action = strdup(action);
216  }
217 
218  if (is_set(ra_caps, pcmk_ra_cap_provider)) {
219  op->provider = strdup(provider);
220  }
221 
222  if (is_set(ra_caps, pcmk_ra_cap_params)) {
223  op->params = params;
224  params = NULL; // so we don't free them in this function
225  }
226 
227  if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_OCF) == 0) {
228  op->opaque->exec = crm_strdup_printf("%s/resource.d/%s/%s",
229  OCF_ROOT_DIR, provider, agent);
230  op->opaque->args[0] = strdup(op->opaque->exec);
231  op->opaque->args[1] = strdup(op->action);
232 
233  } else if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_LSB) == 0) {
235  op->opaque->args[0] = strdup(op->opaque->exec);
236  op->opaque->args[1] = strdup(op->action);
237 
238 #if SUPPORT_SYSTEMD
239  } else if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_SYSTEMD) == 0) {
240  op->opaque->exec = strdup("systemd-dbus");
241 #endif
242 #if SUPPORT_UPSTART
243  } else if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_UPSTART) == 0) {
244  op->opaque->exec = strdup("upstart-dbus");
245 #endif
246 #if SUPPORT_NAGIOS
247  } else if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_NAGIOS) == 0) {
248  op->opaque->exec = dup_file_path(op->agent, NAGIOS_PLUGIN_DIR);
249  op->opaque->args[0] = strdup(op->opaque->exec);
250 
251  if (safe_str_eq(op->action, "monitor") && (op->interval_ms == 0)) {
252  /* Invoke --version for a nagios probe */
253  op->opaque->args[1] = strdup("--version");
254 
255  } else if (op->params) {
256  GHashTableIter iter;
257  char *key = NULL;
258  char *value = NULL;
259  int index = 1;
260  static int args_size = sizeof(op->opaque->args) / sizeof(char *);
261 
262  g_hash_table_iter_init(&iter, op->params);
263 
264  while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value) &&
265  index <= args_size - 3) {
266 
267  if (safe_str_eq(key, XML_ATTR_CRM_VERSION) || strstr(key, CRM_META "_")) {
268  continue;
269  }
270  op->opaque->args[index++] = crm_strdup_printf("--%s", key);
271  op->opaque->args[index++] = strdup(value);
272  }
273  }
274 
275  // Nagios actions don't need to keep the parameters
276  if (op->params != NULL) {
277  g_hash_table_destroy(op->params);
278  op->params = NULL;
279  }
280 #endif
281  } else {
282  crm_err("Unknown resource standard: %s", op->standard);
283  goto return_error;
284  }
285 
286  if(params) {
287  g_hash_table_destroy(params);
288  }
289  return op;
290 
291  return_error:
292  if(params) {
293  g_hash_table_destroy(params);
294  }
296 
297  return NULL;
298 }
299 
300 svc_action_t *
301 services_action_create_generic(const char *exec, const char *args[])
302 {
303  svc_action_t *op;
304  unsigned int cur_arg;
305 
306  op = calloc(1, sizeof(*op));
307  op->opaque = calloc(1, sizeof(svc_action_private_t));
308 
309  op->opaque->exec = strdup(exec);
310  op->opaque->args[0] = strdup(exec);
311 
312  for (cur_arg = 1; args && args[cur_arg - 1]; cur_arg++) {
313  op->opaque->args[cur_arg] = strdup(args[cur_arg - 1]);
314 
315  if (cur_arg == DIMOF(op->opaque->args) - 1) {
316  crm_err("svc_action_t args list not long enough for '%s' execution request.", exec);
317  break;
318  }
319  }
320 
321  return op;
322 }
323 
338 svc_action_t *
339 services_alert_create(const char *id, const char *exec, int timeout,
340  GHashTable *params, int sequence, void *cb_data)
341 {
342  svc_action_t *action = services_action_create_generic(exec, NULL);
343 
344  CRM_ASSERT(action);
345  action->timeout = timeout;
346  action->id = strdup(id);
347  action->params = params;
348  action->sequence = sequence;
349  action->cb_data = cb_data;
350  return action;
351 }
352 
368 int
369 services_action_user(svc_action_t *op, const char *user)
370 {
371  CRM_CHECK((op != NULL) && (user != NULL), return -EINVAL);
372  return crm_user_lookup(user, &(op->opaque->uid), &(op->opaque->gid));
373 }
374 
375 static void
376 set_alert_env(gpointer key, gpointer value, gpointer user_data)
377 {
378  int rc;
379 
380  if (value) {
381  rc = setenv(key, value, 1);
382  } else {
383  rc = unsetenv(key);
384  }
385 
386  if (rc < 0) {
387  crm_perror(LOG_ERR, "setenv %s=%s",
388  (char*)key, (value? (char*)value : ""));
389  } else {
390  crm_trace("setenv %s=%s", (char*)key, (value? (char*)value : ""));
391  }
392 }
393 
394 static void
395 unset_alert_env(gpointer key, gpointer value, gpointer user_data)
396 {
397  if (unsetenv(key) < 0) {
398  crm_perror(LOG_ERR, "unset %s", (char*)key);
399  } else {
400  crm_trace("unset %s", (char*)key);
401  }
402 }
403 
415 gboolean
417 {
418  gboolean responsible;
419 
420  action->synchronous = false;
421  action->opaque->callback = cb;
422  if (action->params) {
423  g_hash_table_foreach(action->params, set_alert_env, NULL);
424  }
425  responsible = services_os_action_execute(action);
426  if (action->params) {
427  g_hash_table_foreach(action->params, unset_alert_env, NULL);
428  }
429  return responsible;
430 }
431 
432 #if SUPPORT_DBUS
433 
440 void
441 services_set_op_pending(svc_action_t *op, DBusPendingCall *pending)
442 {
443  if (op->opaque->pending && (op->opaque->pending != pending)) {
444  if (pending) {
445  crm_info("Lost pending %s DBus call (%p)", op->id, op->opaque->pending);
446  } else {
447  crm_trace("Done with pending %s DBus call (%p)", op->id, op->opaque->pending);
448  }
449  dbus_pending_call_unref(op->opaque->pending);
450  }
451  op->opaque->pending = pending;
452  if (pending) {
453  crm_trace("Updated pending %s DBus call (%p)", op->id, pending);
454  } else {
455  crm_trace("Cleared pending %s DBus call", op->id);
456  }
457 }
458 #endif
459 
460 void
462 {
463  if(op->opaque == NULL) {
464  return;
465  }
466 
467 #if SUPPORT_DBUS
468  if(op->opaque->timerid != 0) {
469  crm_trace("Removing timer for call %s to %s", op->action, op->rsc);
470  g_source_remove(op->opaque->timerid);
471  op->opaque->timerid = 0;
472  }
473 
474  if(op->opaque->pending) {
475  crm_trace("Cleaning up pending dbus call %p %s for %s", op->opaque->pending, op->action, op->rsc);
476  if(dbus_pending_call_get_completed(op->opaque->pending)) {
477  crm_warn("Pending dbus call %s for %s did not complete", op->action, op->rsc);
478  }
479  dbus_pending_call_cancel(op->opaque->pending);
480  dbus_pending_call_unref(op->opaque->pending);
481  op->opaque->pending = NULL;
482  }
483 #endif
484 
485  if (op->opaque->stderr_gsource) {
487  op->opaque->stderr_gsource = NULL;
488  }
489 
490  if (op->opaque->stdout_gsource) {
492  op->opaque->stdout_gsource = NULL;
493  }
494 }
495 
496 void
498 {
499  unsigned int i;
500 
501  if (op == NULL) {
502  return;
503  }
504 
505  /* The operation should be removed from all tracking lists by this point.
506  * If it's not, we have a bug somewhere, so bail. That may lead to a
507  * memory leak, but it's better than a use-after-free segmentation fault.
508  */
509  CRM_CHECK(g_list_find(inflight_ops, op) == NULL, return);
510  CRM_CHECK(g_list_find(blocked_ops, op) == NULL, return);
511  CRM_CHECK((recurring_actions == NULL)
512  || (g_hash_table_lookup(recurring_actions, op->id) == NULL),
513  return);
514 
516 
517  if (op->opaque->repeat_timer) {
518  g_source_remove(op->opaque->repeat_timer);
519  op->opaque->repeat_timer = 0;
520  }
521 
522  free(op->id);
523  free(op->opaque->exec);
524 
525  for (i = 0; i < DIMOF(op->opaque->args); i++) {
526  free(op->opaque->args[i]);
527  }
528 
529  free(op->opaque);
530  free(op->rsc);
531  free(op->action);
532 
533  free(op->standard);
534  free(op->agent);
535  free(op->provider);
536 
537  free(op->stdout_data);
538  free(op->stderr_data);
539 
540  if (op->params) {
541  g_hash_table_destroy(op->params);
542  op->params = NULL;
543  }
544 
545  free(op);
546 }
547 
548 gboolean
550 {
551  crm_info("Cancelling %s operation %s", op->standard, op->id);
552 
553  if (recurring_actions) {
554  g_hash_table_remove(recurring_actions, op->id);
555  }
556 
557  if (op->opaque->repeat_timer) {
558  g_source_remove(op->opaque->repeat_timer);
559  op->opaque->repeat_timer = 0;
560  }
561 
562  return TRUE;
563 }
564 
574 gboolean
575 services_action_cancel(const char *name, const char *action, guint interval_ms)
576 {
577  gboolean cancelled = FALSE;
578  char *id = generate_op_key(name, action, interval_ms);
579  svc_action_t *op = NULL;
580 
581  /* We can only cancel a recurring action */
582  init_recurring_actions();
583  op = g_hash_table_lookup(recurring_actions, id);
584  if (op == NULL) {
585  goto done;
586  }
587 
588  /* Tell operation_finalize() not to reschedule the operation */
589  op->cancel = TRUE;
590 
591  /* Stop tracking it as a recurring operation, and stop its timer */
593 
594  /* If the op has a PID, it's an in-flight child process, so kill it.
595  *
596  * Whether the kill succeeds or fails, the main loop will send the op to
597  * operation_finished() (and thus operation_finalize()) when the process
598  * goes away.
599  */
600  if (op->pid != 0) {
601  crm_info("Terminating in-flight op %s (pid %d) early because it was cancelled",
602  id, op->pid);
603  cancelled = mainloop_child_kill(op->pid);
604  if (cancelled == FALSE) {
605  crm_err("Termination of %s (pid %d) failed", id, op->pid);
606  }
607  goto done;
608  }
609 
610  /* In-flight systemd and upstart ops don't have a pid. The relevant handlers
611  * will call operation_finalize() when the operation completes.
612  * @TODO: Can we request early termination, maybe using
613  * dbus_pending_call_cancel()?
614  */
615  if (inflight_systemd_or_upstart(op)) {
616  crm_info("Will cancel %s op %s when in-flight instance completes",
617  op->standard, op->id);
618  cancelled = FALSE;
619  goto done;
620  }
621 
622  /* Otherwise, operation is not in-flight, just report as cancelled */
624  if (op->opaque->callback) {
625  op->opaque->callback(op);
626  }
627 
628  blocked_ops = g_list_remove(blocked_ops, op);
630  cancelled = TRUE;
631 
632 done:
633  free(id);
634  return cancelled;
635 }
636 
637 gboolean
638 services_action_kick(const char *name, const char *action, guint interval_ms)
639 {
640  svc_action_t * op = NULL;
641  char *id = generate_op_key(name, action, interval_ms);
642 
643  init_recurring_actions();
644  op = g_hash_table_lookup(recurring_actions, id);
645  free(id);
646 
647  if (op == NULL) {
648  return FALSE;
649  }
650 
651 
652  if (op->pid || inflight_systemd_or_upstart(op)) {
653  return TRUE;
654  } else {
655  if (op->opaque->repeat_timer) {
656  g_source_remove(op->opaque->repeat_timer);
657  op->opaque->repeat_timer = 0;
658  }
660  return TRUE;
661  }
662 
663 }
664 
673 static gboolean
674 handle_duplicate_recurring(svc_action_t * op)
675 {
676  svc_action_t * dup = NULL;
677 
678  /* check for duplicates */
679  dup = g_hash_table_lookup(recurring_actions, op->id);
680 
681  if (dup && (dup != op)) {
682  /* update user data */
683  if (op->opaque->callback) {
684  dup->opaque->callback = op->opaque->callback;
685  dup->cb_data = op->cb_data;
686  op->cb_data = NULL;
687  }
688  /* immediately execute the next interval */
689  if (dup->pid != 0) {
690  if (op->opaque->repeat_timer) {
691  g_source_remove(op->opaque->repeat_timer);
692  op->opaque->repeat_timer = 0;
693  }
695  }
696  /* free the duplicate */
698  return TRUE;
699  }
700 
701  return FALSE;
702 }
703 
704 inline static gboolean
705 action_exec_helper(svc_action_t * op)
706 {
707  /* Whether a/synchronous must be decided (op->synchronous) beforehand. */
708  if (op->standard
709  && (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_UPSTART) == 0)) {
710 #if SUPPORT_UPSTART
711  return upstart_job_exec(op);
712 #endif
713  } else if (op->standard && strcasecmp(op->standard,
715 #if SUPPORT_SYSTEMD
716  return systemd_unit_exec(op);
717 #endif
718  } else {
719  return services_os_action_execute(op);
720  }
721  /* The 'op' has probably been freed if the execution functions return TRUE
722  for the asynchronous 'op'. */
723  /* Avoid using the 'op' in here. */
724 
725  return FALSE;
726 }
727 
728 void
730 {
731  if (op == NULL) {
732  return;
733  }
734 
735  CRM_ASSERT(op->synchronous == FALSE);
736 
737  /* keep track of ops that are in-flight to avoid collisions in the same namespace */
738  if (op->rsc) {
739  inflight_ops = g_list_append(inflight_ops, op);
740  }
741 }
742 
749 void
751 {
752  /* Op is no longer in-flight or blocked */
753  inflight_ops = g_list_remove(inflight_ops, op);
754  blocked_ops = g_list_remove(blocked_ops, op);
755 
756  /* Op is no longer blocking other ops, so check if any need to run */
757  handle_blocked_ops();
758 }
759 
760 gboolean
761 services_action_async(svc_action_t * op, void (*action_callback) (svc_action_t *))
762 {
763  op->synchronous = false;
764  if (action_callback) {
765  op->opaque->callback = action_callback;
766  }
767 
768  if (op->interval_ms > 0) {
769  init_recurring_actions();
770  if (handle_duplicate_recurring(op) == TRUE) {
771  /* entry rescheduled, dup freed */
772  /* exit early */
773  return TRUE;
774  }
775  g_hash_table_replace(recurring_actions, op->id, op);
776  }
777 
778  if (op->rsc && is_op_blocked(op->rsc)) {
779  blocked_ops = g_list_append(blocked_ops, op);
780  return TRUE;
781  }
782 
783  return action_exec_helper(op);
784 }
785 
786 
787 static gboolean processing_blocked_ops = FALSE;
788 
789 gboolean
790 is_op_blocked(const char *rsc)
791 {
792  GList *gIter = NULL;
793  svc_action_t *op = NULL;
794 
795  for (gIter = inflight_ops; gIter != NULL; gIter = gIter->next) {
796  op = gIter->data;
797  if (safe_str_eq(op->rsc, rsc)) {
798  return TRUE;
799  }
800  }
801 
802  return FALSE;
803 }
804 
805 static void
806 handle_blocked_ops(void)
807 {
808  GList *executed_ops = NULL;
809  GList *gIter = NULL;
810  svc_action_t *op = NULL;
811  gboolean res = FALSE;
812 
813  if (processing_blocked_ops) {
814  /* avoid nested calling of this function */
815  return;
816  }
817 
818  processing_blocked_ops = TRUE;
819 
820  /* n^2 operation here, but blocked ops are incredibly rare. this list
821  * will be empty 99% of the time. */
822  for (gIter = blocked_ops; gIter != NULL; gIter = gIter->next) {
823  op = gIter->data;
824  if (is_op_blocked(op->rsc)) {
825  continue;
826  }
827  executed_ops = g_list_append(executed_ops, op);
828  res = action_exec_helper(op);
829  if (res == FALSE) {
831  /* this can cause this function to be called recursively
832  * which is why we have processing_blocked_ops static variable */
833  operation_finalize(op);
834  }
835  }
836 
837  for (gIter = executed_ops; gIter != NULL; gIter = gIter->next) {
838  op = gIter->data;
839  blocked_ops = g_list_remove(blocked_ops, op);
840  }
841  g_list_free(executed_ops);
842 
843  processing_blocked_ops = FALSE;
844 }
845 
846 #if SUPPORT_NAGIOS
847 static int
848 nagios_get_metadata(const char *type, char **output)
849 {
850  int rc = pcmk_ok;
851  FILE *file_strm = NULL;
852  int start = 0, length = 0, read_len = 0;
853  char *metadata_file = crm_strdup_printf("%s/%s.xml",
854  NAGIOS_METADATA_DIR, type);
855 
856  file_strm = fopen(metadata_file, "r");
857  if (file_strm == NULL) {
858  crm_err("Metadata file %s does not exist", metadata_file);
859  free(metadata_file);
860  return -EIO;
861  }
862 
863  /* see how big the file is */
864  start = ftell(file_strm);
865  fseek(file_strm, 0L, SEEK_END);
866  length = ftell(file_strm);
867  fseek(file_strm, 0L, start);
868 
869  CRM_ASSERT(length >= 0);
870  CRM_ASSERT(start == ftell(file_strm));
871 
872  if (length <= 0) {
873  crm_info("%s was not valid", metadata_file);
874  free(*output);
875  *output = NULL;
876  rc = -EIO;
877 
878  } else {
879  crm_trace("Reading %d bytes from file", length);
880  *output = calloc(1, (length + 1));
881  read_len = fread(*output, 1, length, file_strm);
882  if (read_len != length) {
883  crm_err("Calculated and read bytes differ: %d vs. %d",
884  length, read_len);
885  free(*output);
886  *output = NULL;
887  rc = -EIO;
888  }
889  }
890 
891  fclose(file_strm);
892  free(metadata_file);
893  return rc;
894 }
895 #endif
896 
897 static gboolean
898 action_get_metadata(svc_action_t *op)
899 {
900  const char *class = op->standard;
901 
902  if (op->agent == NULL) {
903  crm_err("meta-data requested without specifying agent");
904  return FALSE;
905  }
906 
907  if (class == NULL) {
908  crm_err("meta-data requested for agent %s without specifying class",
909  op->agent);
910  return FALSE;
911  }
912 
913  if (!strcmp(class, PCMK_RESOURCE_CLASS_SERVICE)) {
914  class = resources_find_service_class(op->agent);
915  }
916 
917  if (class == NULL) {
918  crm_err("meta-data requested for %s, but could not determine class",
919  op->agent);
920  return FALSE;
921  }
922 
923  if (safe_str_eq(class, PCMK_RESOURCE_CLASS_LSB)) {
924  return (services__get_lsb_metadata(op->agent, &op->stdout_data) >= 0);
925  }
926 
927 #if SUPPORT_NAGIOS
929  return (nagios_get_metadata(op->agent, &op->stdout_data) >= 0);
930  }
931 #endif
932 
933  return action_exec_helper(op);
934 }
935 
936 gboolean
938 {
939  gboolean rc = TRUE;
940 
941  if (op == NULL) {
942  crm_trace("No operation to execute");
943  return FALSE;
944  }
945 
946  op->synchronous = true;
947 
948  if (safe_str_eq(op->action, "meta-data")) {
949  /* Synchronous meta-data operations are handled specially. Since most
950  * resource classes don't provide any meta-data, it has to be
951  * synthesized from available information about the agent.
952  *
953  * services_action_async() doesn't treat meta-data actions specially, so
954  * it will result in an error for classes that don't support the action.
955  */
956  rc = action_get_metadata(op);
957  } else {
958  rc = action_exec_helper(op);
959  }
960  crm_trace(" > " CRM_OP_FMT ": %s = %d",
961  op->rsc, op->action, op->interval_ms, op->opaque->exec, op->rc);
962  if (op->stdout_data) {
963  crm_trace(" > stdout: %s", op->stdout_data);
964  }
965  if (op->stderr_data) {
966  crm_trace(" > stderr: %s", op->stderr_data);
967  }
968  return rc;
969 }
970 
971 GList *
972 get_directory_list(const char *root, gboolean files, gboolean executable)
973 {
974  return services_os_get_directory_list(root, files, executable);
975 }
976 
977 GList *
979 {
980  GList *standards = NULL;
981  GList *agents = NULL;
982 
983  standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_OCF));
984  standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_LSB));
985  standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_SERVICE));
986 
987 #if SUPPORT_SYSTEMD
988  agents = systemd_unit_listall();
989  if (agents) {
990  standards = g_list_append(standards,
992  g_list_free_full(agents, free);
993  }
994 #endif
995 
996 #if SUPPORT_UPSTART
997  agents = upstart_job_listall();
998  if (agents) {
999  standards = g_list_append(standards,
1000  strdup(PCMK_RESOURCE_CLASS_UPSTART));
1001  g_list_free_full(agents, free);
1002  }
1003 #endif
1004 
1005 #if SUPPORT_NAGIOS
1007  if (agents) {
1008  standards = g_list_append(standards,
1009  strdup(PCMK_RESOURCE_CLASS_NAGIOS));
1010  g_list_free_full(agents, free);
1011  }
1012 #endif
1013 
1014  return standards;
1015 }
1016 
1017 GList *
1018 resources_list_providers(const char *standard)
1019 {
1020  if (is_set(pcmk_get_ra_caps(standard), pcmk_ra_cap_provider)) {
1022  }
1023 
1024  return NULL;
1025 }
1026 
1027 GList *
1028 resources_list_agents(const char *standard, const char *provider)
1029 {
1030  if ((standard == NULL)
1031  || (strcasecmp(standard, PCMK_RESOURCE_CLASS_SERVICE) == 0)) {
1032 
1033  GList *tmp1;
1034  GList *tmp2;
1035  GList *result = services__list_lsb_agents();
1036 
1037  if (standard == NULL) {
1038  tmp1 = result;
1039  tmp2 = resources_os_list_ocf_agents(NULL);
1040  if (tmp2) {
1041  result = g_list_concat(tmp1, tmp2);
1042  }
1043  }
1044 #if SUPPORT_SYSTEMD
1045  tmp1 = result;
1046  tmp2 = systemd_unit_listall();
1047  if (tmp2) {
1048  result = g_list_concat(tmp1, tmp2);
1049  }
1050 #endif
1051 
1052 #if SUPPORT_UPSTART
1053  tmp1 = result;
1054  tmp2 = upstart_job_listall();
1055  if (tmp2) {
1056  result = g_list_concat(tmp1, tmp2);
1057  }
1058 #endif
1059 
1060  return result;
1061 
1062  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_OCF) == 0) {
1063  return resources_os_list_ocf_agents(provider);
1064  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_LSB) == 0) {
1065  return services__list_lsb_agents();
1066 #if SUPPORT_SYSTEMD
1067  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_SYSTEMD) == 0) {
1068  return systemd_unit_listall();
1069 #endif
1070 #if SUPPORT_UPSTART
1071  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_UPSTART) == 0) {
1072  return upstart_job_listall();
1073 #endif
1074 #if SUPPORT_NAGIOS
1075  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_NAGIOS) == 0) {
1077 #endif
1078  }
1079 
1080  return NULL;
1081 }
Services API.
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:165
void(* callback)(svc_action_t *op)
A dumping ground.
guint interval_ms
Definition: services.h:150
GList * resources_list_providers(const char *standard)
Get a list of providers.
Definition: services.c:1018
char * standard
Definition: services.h:152
gboolean upstart_job_exists(const char *name)
Definition: upstart.c:230
gboolean mainloop_child_kill(pid_t pid)
Definition: mainloop.c:1036
char * id
Definition: services.h:147
mainloop_io_t * stderr_gsource
GList * resources_os_list_ocf_agents(const char *provider)
GList * resources_os_list_ocf_providers(void)
#define PCMK_RESOURCE_CLASS_SYSTEMD
Definition: services.h:44
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:761
char * rsc
Definition: services.h:148
int crm_user_lookup(const char *name, uid_t *uid, gid_t *gid)
Definition: utils.c:400
gboolean services_os_action_execute(svc_action_t *op)
G_GNUC_INTERNAL GList * resources_os_list_nagios_agents(void)
svc_action_flags
Definition: services.h:140
gboolean upstart_job_exec(svc_action_t *op)
Definition: upstart.c:417
gboolean is_op_blocked(const char *rsc)
Definition: services.c:790
Wrappers for and extensions to glib mainloop.
char * services__lsb_agent_path(const char *agent)
Definition: services_lsb.c:249
svc_action_t * services_action_create_generic(const char *exec, const char *args[])
Definition: services.c:301
int services__get_lsb_metadata(const char *type, char **output)
Definition: services_lsb.c:100
GList * services__list_lsb_agents(void)
Definition: services_lsb.c:243
enum svc_action_flags flags
Definition: services.h:166
#define crm_warn(fmt, args...)
Definition: logging.h:250
#define PCMK_RESOURCE_CLASS_OCF
Definition: services.h:41
gboolean cancel_recurring_action(svc_action_t *op)
Definition: services.c:549
#define CRM_OP_FMT
Definition: crm_internal.h:131
svc_action_private_t * opaque
Definition: services.h:179
GList * upstart_job_listall(void)
Definition: upstart.c:149
#define OCF_ROOT_DIR
Definition: services.h:28
#define crm_debug(fmt, args...)
Definition: logging.h:254
gboolean operation_finalize(svc_action_t *op)
char * stdout_data
Definition: services.h:169
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:339
gboolean systemd_unit_exists(const char *name)
Definition: systemd.c:459
#define PCMK_RESOURCE_CLASS_SERVICE
Definition: services.h:42
GHashTable * params
Definition: services.h:157
#define crm_trace(fmt, args...)
Definition: logging.h:255
int setenv(const char *name, const char *value, int why)
gboolean services_alert_async(svc_action_t *action, void(*cb)(svc_action_t *op))
Execute an alert agent action.
Definition: services.c:416
char * agent
Definition: services.h:154
int synchronous
Definition: services.h:165
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard.
Definition: agents.c:29
gboolean services_action_sync(svc_action_t *op)
Definition: services.c:937
int sequence
Definition: services.h:163
GList * systemd_unit_listall(void)
Definition: systemd.c:362
const char * resources_find_service_class(const char *agent)
Find first service class that can provide a specified agent.
Definition: services.c:62
GList * resources_list_agents(const char *standard, const char *provider)
Get a list of resource agents.
Definition: services.c:1028
char * args[MAX_ARGC]
void services_add_inflight_op(svc_action_t *op)
Definition: services.c:729
GList * resources_list_standards(void)
Definition: services.c:978
void services_untrack_op(svc_action_t *op)
Definition: services.c:750
char * action
Definition: services.h:149
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:972
#define PCMK_RESOURCE_CLASS_NAGIOS
Definition: services.h:46
#define PCMK_RESOURCE_CLASS_LSB
Definition: services.h:43
#define crm_perror(level, fmt, args...)
Log a system error message.
Definition: logging.h:227
#define NAGIOS_PLUGIN_DIR
Definition: config.h:525
svc_action_t * resources_action_create(const char *name, const char *standard, const char *provider, const char *agent, const char *action, guint interval_ms, int timeout, GHashTable *params, enum svc_action_flags flags)
Create a new resource action.
Definition: services.c:158
#define CRM_META
Definition: crm.h:47
#define crm_err(fmt, args...)
Definition: logging.h:249
#define CRM_ASSERT(expr)
Definition: results.h:20
#define PCMK_RESOURCE_CLASS_UPSTART
Definition: services.h:45
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:369
#define DIMOF(a)
Definition: crm.h:33
#define uint32_t
Definition: stdint.in.h:158
mainloop_io_t * stdout_gsource
#define XML_ATTR_CRM_VERSION
Definition: msg_xml.h:77
#define pcmk_ok
Definition: results.h:35
void mainloop_del_fd(mainloop_io_t *client)
Definition: mainloop.c:848
void * cb_data
Definition: services.h:177
void services_action_cleanup(svc_action_t *op)
Definition: services.c:461
#define safe_str_eq(a, b)
Definition: util.h:54
void services_action_free(svc_action_t *op)
Definition: services.c:497
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
char * provider
Definition: services.h:153
gboolean systemd_unit_exec(svc_action_t *op)
Definition: systemd.c:798
#define crm_info(fmt, args...)
Definition: logging.h:252
#define NAGIOS_METADATA_DIR
Definition: config.h:522
char * generate_op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key.
Definition: operations.c:37
gboolean services_action_cancel(const char *name, const char *action, guint interval_ms)
Cancel a recurring action.
Definition: services.c:575
gboolean services_action_kick(const char *name, const char *action, guint interval_ms)
Definition: services.c:638
uint64_t flags
Definition: remote.c:148
bool services__lsb_agent_exists(const char *agent)
Definition: services_lsb.c:256
enum crm_ais_msg_types type
Definition: internal.h:80
char * stderr_data
Definition: services.h:168