This source file includes following definitions.
- resources_find_service_class
- init_recurring_actions
- inflight_systemd_or_upstart
- expand_resource_class
- dup_file_path
- resources_action_create
- services_action_create_generic
- services_alert_create
- services_action_user
- services_alert_async
- services_set_op_pending
- services_action_cleanup
- services_action_free
- cancel_recurring_action
- services_action_cancel
- services_action_kick
- handle_duplicate_recurring
- action_exec_helper
- services_add_inflight_op
- services_untrack_op
- services_action_async_fork_notify
- services_action_async
- is_op_blocked
- handle_blocked_ops
- action_get_metadata
- services_action_sync
- get_directory_list
- resources_list_standards
- resources_list_providers
- resources_list_agents
- resources_agent_exists
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #ifndef _GNU_SOURCE
13 # define _GNU_SOURCE
14 #endif
15
16 #include <sys/types.h>
17 #include <stdio.h>
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/stonith-ng.h>
27 #include <crm/msg_xml.h>
28 #include "services_private.h"
29 #include "services_lsb.h"
30
31 #if SUPPORT_UPSTART
32 # include <upstart.h>
33 #endif
34
35 #if SUPPORT_SYSTEMD
36 # include <systemd.h>
37 #endif
38
39 #if SUPPORT_NAGIOS
40 # include <services_nagios.h>
41 #endif
42
43
44
45 static int operations = 0;
46 static GHashTable *recurring_actions = NULL;
47
48
49
50 static GList *blocked_ops = NULL;
51
52
53 static GList *inflight_ops = NULL;
54
55 static void handle_blocked_ops(void);
56
57
58
59
60
61
62
63
64
65
66
67
68 const char *
69 resources_find_service_class(const char *agent)
70 {
71 if (services__lsb_agent_exists(agent)) {
72 return PCMK_RESOURCE_CLASS_LSB;
73 }
74
75 #if SUPPORT_SYSTEMD
76 if (systemd_unit_exists(agent)) {
77 return PCMK_RESOURCE_CLASS_SYSTEMD;
78 }
79 #endif
80
81 #if SUPPORT_UPSTART
82 if (upstart_job_exists(agent)) {
83 return PCMK_RESOURCE_CLASS_UPSTART;
84 }
85 #endif
86 return NULL;
87 }
88
89 static inline void
90 init_recurring_actions(void)
91 {
92 if (recurring_actions == NULL) {
93 recurring_actions = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
94 NULL);
95 }
96 }
97
98
99
100
101
102
103
104
105
106 static inline gboolean
107 inflight_systemd_or_upstart(svc_action_t *op)
108 {
109 return pcmk__strcase_any_of(op->standard, PCMK_RESOURCE_CLASS_SYSTEMD,
110 PCMK_RESOURCE_CLASS_UPSTART, NULL) &&
111 g_list_find(inflight_ops, op) != NULL;
112 }
113
114
115
116
117
118
119
120
121
122
123
124
125
126 static char *
127 expand_resource_class(const char *rsc, const char *standard, const char *agent)
128 {
129 char *expanded_class = NULL;
130
131 if (strcasecmp(standard, PCMK_RESOURCE_CLASS_SERVICE) == 0) {
132 const char *found_class = resources_find_service_class(agent);
133
134 if (found_class) {
135 crm_debug("Found %s agent %s for %s", found_class, agent, rsc);
136 expanded_class = strdup(found_class);
137 } else {
138 crm_info("Assuming resource class lsb for agent %s for %s",
139 agent, rsc);
140 expanded_class = strdup(PCMK_RESOURCE_CLASS_LSB);
141 }
142 } else {
143 expanded_class = strdup(standard);
144 }
145 CRM_ASSERT(expanded_class);
146 return expanded_class;
147 }
148
149
150
151
152
153
154
155
156
157 static char *
158 dup_file_path(const char *filename, const char *dirname)
159 {
160 return (*filename == '/')? strdup(filename)
161 : crm_strdup_printf("%s/%s", dirname, filename);
162 }
163
164 svc_action_t *
165 resources_action_create(const char *name, const char *standard,
166 const char *provider, const char *agent,
167 const char *action, guint interval_ms, int timeout,
168 GHashTable *params, enum svc_action_flags flags)
169 {
170 svc_action_t *op = NULL;
171 uint32_t ra_caps = 0;
172
173
174
175
176
177
178 if (pcmk__str_empty(name)) {
179 crm_err("Cannot create operation without resource name");
180 goto return_error;
181 }
182
183 if (pcmk__str_empty(standard)) {
184 crm_err("Cannot create operation for %s without resource class", name);
185 goto return_error;
186 }
187 ra_caps = pcmk_get_ra_caps(standard);
188
189 if (pcmk_is_set(ra_caps, pcmk_ra_cap_provider)
190 && pcmk__str_empty(provider)) {
191 crm_err("Cannot create operation for %s without provider", name);
192 goto return_error;
193 }
194
195 if (pcmk__str_empty(agent)) {
196 crm_err("Cannot create operation for %s without agent name", name);
197 goto return_error;
198 }
199
200 if (pcmk__str_empty(action)) {
201 crm_err("Cannot create operation for %s without operation name", name);
202 goto return_error;
203 }
204
205
206
207
208
209 op = calloc(1, sizeof(svc_action_t));
210 op->opaque = calloc(1, sizeof(svc_action_private_t));
211 op->rsc = strdup(name);
212 op->interval_ms = interval_ms;
213 op->timeout = timeout;
214 op->standard = expand_resource_class(name, standard, agent);
215 op->agent = strdup(agent);
216 op->sequence = ++operations;
217 op->flags = flags;
218 op->id = pcmk__op_key(name, action, interval_ms);
219
220 if (pcmk_is_set(ra_caps, pcmk_ra_cap_status)
221 && pcmk__str_eq(action, "monitor", pcmk__str_casei)) {
222
223 op->action = strdup("status");
224 } else {
225 op->action = strdup(action);
226 }
227
228 if (pcmk_is_set(ra_caps, pcmk_ra_cap_provider)) {
229 op->provider = strdup(provider);
230 }
231
232 if (pcmk_is_set(ra_caps, pcmk_ra_cap_params)) {
233 op->params = params;
234 params = NULL;
235 }
236
237 if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_OCF) == 0) {
238 op->opaque->exec = crm_strdup_printf("%s/resource.d/%s/%s",
239 OCF_ROOT_DIR, provider, agent);
240 op->opaque->args[0] = strdup(op->opaque->exec);
241 op->opaque->args[1] = strdup(op->action);
242
243 } else if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_LSB) == 0) {
244 op->opaque->exec = services__lsb_agent_path(op->agent);
245 op->opaque->args[0] = strdup(op->opaque->exec);
246 op->opaque->args[1] = strdup(op->action);
247
248 #if SUPPORT_SYSTEMD
249 } else if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_SYSTEMD) == 0) {
250 op->opaque->exec = strdup("systemd-dbus");
251 #endif
252 #if SUPPORT_UPSTART
253 } else if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_UPSTART) == 0) {
254 op->opaque->exec = strdup("upstart-dbus");
255 #endif
256 #if SUPPORT_NAGIOS
257 } else if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_NAGIOS) == 0) {
258 op->opaque->exec = dup_file_path(op->agent, NAGIOS_PLUGIN_DIR);
259 op->opaque->args[0] = strdup(op->opaque->exec);
260
261 if (pcmk__str_eq(op->action, "monitor", pcmk__str_casei) && (op->interval_ms == 0)) {
262
263 op->opaque->args[1] = strdup("--version");
264
265 } else if (op->params) {
266 GHashTableIter iter;
267 char *key = NULL;
268 char *value = NULL;
269 int index = 1;
270 static int args_size = sizeof(op->opaque->args) / sizeof(char *);
271
272 g_hash_table_iter_init(&iter, op->params);
273
274 while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value) &&
275 index <= args_size - 3) {
276
277 if (pcmk__str_eq(key, XML_ATTR_CRM_VERSION, pcmk__str_casei) || strstr(key, CRM_META "_")) {
278 continue;
279 }
280 op->opaque->args[index++] = crm_strdup_printf("--%s", key);
281 op->opaque->args[index++] = strdup(value);
282 }
283 }
284
285
286 if (op->params != NULL) {
287 g_hash_table_destroy(op->params);
288 op->params = NULL;
289 }
290 #endif
291 } else {
292 crm_err("Unknown resource standard: %s", op->standard);
293 goto return_error;
294 }
295
296 if(params) {
297 g_hash_table_destroy(params);
298 }
299 return op;
300
301 return_error:
302 if(params) {
303 g_hash_table_destroy(params);
304 }
305 services_action_free(op);
306
307 return NULL;
308 }
309
310 svc_action_t *
311 services_action_create_generic(const char *exec, const char *args[])
312 {
313 svc_action_t *op;
314 unsigned int cur_arg;
315
316 op = calloc(1, sizeof(*op));
317 op->opaque = calloc(1, sizeof(svc_action_private_t));
318
319 op->opaque->exec = strdup(exec);
320 op->opaque->args[0] = strdup(exec);
321
322 for (cur_arg = 1; args && args[cur_arg - 1]; cur_arg++) {
323 op->opaque->args[cur_arg] = strdup(args[cur_arg - 1]);
324
325 if (cur_arg == DIMOF(op->opaque->args) - 1) {
326 crm_err("svc_action_t args list not long enough for '%s' execution request.", exec);
327 break;
328 }
329 }
330
331 return op;
332 }
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348 svc_action_t *
349 services_alert_create(const char *id, const char *exec, int timeout,
350 GHashTable *params, int sequence, void *cb_data)
351 {
352 svc_action_t *action = services_action_create_generic(exec, NULL);
353
354 CRM_ASSERT(action);
355 action->timeout = timeout;
356 action->id = strdup(id);
357 action->params = params;
358 action->sequence = sequence;
359 action->cb_data = cb_data;
360 return action;
361 }
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378 int
379 services_action_user(svc_action_t *op, const char *user)
380 {
381 CRM_CHECK((op != NULL) && (user != NULL), return -EINVAL);
382 return crm_user_lookup(user, &(op->opaque->uid), &(op->opaque->gid));
383 }
384
385
386
387
388
389
390
391
392
393
394
395
396 gboolean
397 services_alert_async(svc_action_t *action, void (*cb)(svc_action_t *op))
398 {
399 action->synchronous = false;
400 action->opaque->callback = cb;
401 return services_os_action_execute(action);
402 }
403
404 #if SUPPORT_DBUS
405
406
407
408
409
410
411
412 void
413 services_set_op_pending(svc_action_t *op, DBusPendingCall *pending)
414 {
415 if (op->opaque->pending && (op->opaque->pending != pending)) {
416 if (pending) {
417 crm_info("Lost pending %s DBus call (%p)", op->id, op->opaque->pending);
418 } else {
419 crm_trace("Done with pending %s DBus call (%p)", op->id, op->opaque->pending);
420 }
421 dbus_pending_call_unref(op->opaque->pending);
422 }
423 op->opaque->pending = pending;
424 if (pending) {
425 crm_trace("Updated pending %s DBus call (%p)", op->id, pending);
426 } else {
427 crm_trace("Cleared pending %s DBus call", op->id);
428 }
429 }
430 #endif
431
432 void
433 services_action_cleanup(svc_action_t * op)
434 {
435 if ((op == NULL) || (op->opaque == NULL)) {
436 return;
437 }
438
439 #if SUPPORT_DBUS
440 if(op->opaque->timerid != 0) {
441 crm_trace("Removing timer for call %s to %s", op->action, op->rsc);
442 g_source_remove(op->opaque->timerid);
443 op->opaque->timerid = 0;
444 }
445
446 if(op->opaque->pending) {
447 if (dbus_pending_call_get_completed(op->opaque->pending)) {
448
449 crm_warn("Result of %s op %s was unhandled",
450 op->standard, op->id);
451 } else {
452 crm_debug("Will ignore any result of canceled %s op %s",
453 op->standard, op->id);
454 }
455 dbus_pending_call_cancel(op->opaque->pending);
456 services_set_op_pending(op, NULL);
457 }
458 #endif
459
460 if (op->opaque->stderr_gsource) {
461 mainloop_del_fd(op->opaque->stderr_gsource);
462 op->opaque->stderr_gsource = NULL;
463 }
464
465 if (op->opaque->stdout_gsource) {
466 mainloop_del_fd(op->opaque->stdout_gsource);
467 op->opaque->stdout_gsource = NULL;
468 }
469 }
470
471 void
472 services_action_free(svc_action_t * op)
473 {
474 unsigned int i;
475
476 if (op == NULL) {
477 return;
478 }
479
480
481
482
483
484 CRM_CHECK(g_list_find(inflight_ops, op) == NULL, return);
485 CRM_CHECK(g_list_find(blocked_ops, op) == NULL, return);
486 CRM_CHECK((recurring_actions == NULL)
487 || (g_hash_table_lookup(recurring_actions, op->id) == NULL),
488 return);
489
490 services_action_cleanup(op);
491
492 if (op->opaque->repeat_timer) {
493 g_source_remove(op->opaque->repeat_timer);
494 op->opaque->repeat_timer = 0;
495 }
496
497 free(op->id);
498 free(op->opaque->exec);
499
500 for (i = 0; i < DIMOF(op->opaque->args); i++) {
501 free(op->opaque->args[i]);
502 }
503
504 free(op->opaque);
505 free(op->rsc);
506 free(op->action);
507
508 free(op->standard);
509 free(op->agent);
510 free(op->provider);
511
512 free(op->stdout_data);
513 free(op->stderr_data);
514
515 if (op->params) {
516 g_hash_table_destroy(op->params);
517 op->params = NULL;
518 }
519
520 free(op);
521 }
522
523 gboolean
524 cancel_recurring_action(svc_action_t * op)
525 {
526 crm_info("Cancelling %s operation %s", op->standard, op->id);
527
528 if (recurring_actions) {
529 g_hash_table_remove(recurring_actions, op->id);
530 }
531
532 if (op->opaque->repeat_timer) {
533 g_source_remove(op->opaque->repeat_timer);
534 op->opaque->repeat_timer = 0;
535 }
536
537 return TRUE;
538 }
539
540
541
542
543
544
545
546
547
548
549 gboolean
550 services_action_cancel(const char *name, const char *action, guint interval_ms)
551 {
552 gboolean cancelled = FALSE;
553 char *id = pcmk__op_key(name, action, interval_ms);
554 svc_action_t *op = NULL;
555
556
557 init_recurring_actions();
558 op = g_hash_table_lookup(recurring_actions, id);
559 if (op == NULL) {
560 goto done;
561 }
562
563
564 op->cancel = TRUE;
565
566
567 cancel_recurring_action(op);
568
569
570
571
572
573
574
575 if (op->pid != 0) {
576 crm_info("Terminating in-flight op %s[%d] early because it was cancelled",
577 id, op->pid);
578 cancelled = mainloop_child_kill(op->pid);
579 if (cancelled == FALSE) {
580 crm_err("Termination of %s[%d] failed", id, op->pid);
581 }
582 goto done;
583 }
584
585 #if SUPPORT_DBUS
586
587 if (inflight_systemd_or_upstart(op)) {
588 inflight_ops = g_list_remove(inflight_ops, op);
589
590
591
592
593 services_action_cleanup(op);
594 }
595 #endif
596
597
598
599
600
601 op->status = PCMK_LRM_OP_CANCELLED;
602 if (op->opaque->callback) {
603 op->opaque->callback(op);
604 }
605
606 blocked_ops = g_list_remove(blocked_ops, op);
607 services_action_free(op);
608 cancelled = TRUE;
609
610
611 done:
612 free(id);
613 return cancelled;
614 }
615
616 gboolean
617 services_action_kick(const char *name, const char *action, guint interval_ms)
618 {
619 svc_action_t * op = NULL;
620 char *id = pcmk__op_key(name, action, interval_ms);
621
622 init_recurring_actions();
623 op = g_hash_table_lookup(recurring_actions, id);
624 free(id);
625
626 if (op == NULL) {
627 return FALSE;
628 }
629
630
631 if (op->pid || inflight_systemd_or_upstart(op)) {
632 return TRUE;
633 } else {
634 if (op->opaque->repeat_timer) {
635 g_source_remove(op->opaque->repeat_timer);
636 op->opaque->repeat_timer = 0;
637 }
638 recurring_action_timer(op);
639 return TRUE;
640 }
641
642 }
643
644
645
646
647
648
649
650
651
652 static gboolean
653 handle_duplicate_recurring(svc_action_t * op)
654 {
655 svc_action_t * dup = NULL;
656
657
658 dup = g_hash_table_lookup(recurring_actions, op->id);
659
660 if (dup && (dup != op)) {
661
662 if (op->opaque->callback) {
663 dup->opaque->callback = op->opaque->callback;
664 dup->cb_data = op->cb_data;
665 op->cb_data = NULL;
666 }
667
668 if (dup->pid != 0) {
669 if (op->opaque->repeat_timer) {
670 g_source_remove(op->opaque->repeat_timer);
671 op->opaque->repeat_timer = 0;
672 }
673 recurring_action_timer(dup);
674 }
675
676 services_action_free(op);
677 return TRUE;
678 }
679
680 return FALSE;
681 }
682
683 inline static gboolean
684 action_exec_helper(svc_action_t * op)
685 {
686
687 if (op->standard
688 && (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_UPSTART) == 0)) {
689 #if SUPPORT_UPSTART
690 return upstart_job_exec(op);
691 #endif
692 } else if (op->standard && strcasecmp(op->standard,
693 PCMK_RESOURCE_CLASS_SYSTEMD) == 0) {
694 #if SUPPORT_SYSTEMD
695 return systemd_unit_exec(op);
696 #endif
697 } else {
698 return services_os_action_execute(op);
699 }
700
701
702
703
704 return FALSE;
705 }
706
707 void
708 services_add_inflight_op(svc_action_t * op)
709 {
710 if (op == NULL) {
711 return;
712 }
713
714 CRM_ASSERT(op->synchronous == FALSE);
715
716
717 if (op->rsc) {
718 inflight_ops = g_list_append(inflight_ops, op);
719 }
720 }
721
722
723
724
725
726
727
728 void
729 services_untrack_op(svc_action_t *op)
730 {
731
732 inflight_ops = g_list_remove(inflight_ops, op);
733 blocked_ops = g_list_remove(blocked_ops, op);
734
735
736 handle_blocked_ops();
737 }
738
739 gboolean
740 services_action_async_fork_notify(svc_action_t * op,
741 void (*action_callback) (svc_action_t *),
742 void (*action_fork_callback) (svc_action_t *))
743 {
744 op->synchronous = false;
745 if (action_callback) {
746 op->opaque->callback = action_callback;
747 }
748 if (action_fork_callback) {
749 op->opaque->fork_callback = action_fork_callback;
750 }
751
752 if (op->interval_ms > 0) {
753 init_recurring_actions();
754 if (handle_duplicate_recurring(op) == TRUE) {
755
756
757 return TRUE;
758 }
759 g_hash_table_replace(recurring_actions, op->id, op);
760 }
761
762 if (!pcmk_is_set(op->flags, SVC_ACTION_NON_BLOCKED)
763 && op->rsc && is_op_blocked(op->rsc)) {
764 blocked_ops = g_list_append(blocked_ops, op);
765 return TRUE;
766 }
767
768 return action_exec_helper(op);
769 }
770
771 gboolean
772 services_action_async(svc_action_t * op,
773 void (*action_callback) (svc_action_t *))
774 {
775 return services_action_async_fork_notify(op, action_callback, NULL);
776 }
777
778 static gboolean processing_blocked_ops = FALSE;
779
780 gboolean
781 is_op_blocked(const char *rsc)
782 {
783 GList *gIter = NULL;
784 svc_action_t *op = NULL;
785
786 for (gIter = inflight_ops; gIter != NULL; gIter = gIter->next) {
787 op = gIter->data;
788 if (pcmk__str_eq(op->rsc, rsc, pcmk__str_casei)) {
789 return TRUE;
790 }
791 }
792
793 return FALSE;
794 }
795
796 static void
797 handle_blocked_ops(void)
798 {
799 GList *executed_ops = NULL;
800 GList *gIter = NULL;
801 svc_action_t *op = NULL;
802 gboolean res = FALSE;
803
804 if (processing_blocked_ops) {
805
806 return;
807 }
808
809 processing_blocked_ops = TRUE;
810
811
812
813 for (gIter = blocked_ops; gIter != NULL; gIter = gIter->next) {
814 op = gIter->data;
815 if (is_op_blocked(op->rsc)) {
816 continue;
817 }
818 executed_ops = g_list_append(executed_ops, op);
819 res = action_exec_helper(op);
820 if (res == FALSE) {
821 op->status = PCMK_LRM_OP_ERROR;
822
823
824 operation_finalize(op);
825 }
826 }
827
828 for (gIter = executed_ops; gIter != NULL; gIter = gIter->next) {
829 op = gIter->data;
830 blocked_ops = g_list_remove(blocked_ops, op);
831 }
832 g_list_free(executed_ops);
833
834 processing_blocked_ops = FALSE;
835 }
836
837 static gboolean
838 action_get_metadata(svc_action_t *op)
839 {
840 const char *class = op->standard;
841
842 if (op->agent == NULL) {
843 crm_err("meta-data requested without specifying agent");
844 return FALSE;
845 }
846
847 if (class == NULL) {
848 crm_err("meta-data requested for agent %s without specifying class",
849 op->agent);
850 return FALSE;
851 }
852
853 if (!strcmp(class, PCMK_RESOURCE_CLASS_SERVICE)) {
854 class = resources_find_service_class(op->agent);
855 }
856
857 if (class == NULL) {
858 crm_err("meta-data requested for %s, but could not determine class",
859 op->agent);
860 return FALSE;
861 }
862
863 if (pcmk__str_eq(class, PCMK_RESOURCE_CLASS_LSB, pcmk__str_casei)) {
864 return (services__get_lsb_metadata(op->agent, &op->stdout_data) >= 0);
865 }
866
867 #if SUPPORT_NAGIOS
868 if (pcmk__str_eq(class, PCMK_RESOURCE_CLASS_NAGIOS, pcmk__str_casei)) {
869 return services__get_nagios_metadata(op->agent, &op->stdout_data) >= 0;
870 }
871 #endif
872
873 return action_exec_helper(op);
874 }
875
876 gboolean
877 services_action_sync(svc_action_t * op)
878 {
879 gboolean rc = TRUE;
880
881 if (op == NULL) {
882 crm_trace("No operation to execute");
883 return FALSE;
884 }
885
886 op->synchronous = true;
887
888 if (pcmk__str_eq(op->action, "meta-data", pcmk__str_casei)) {
889
890
891
892
893
894
895
896 rc = action_get_metadata(op);
897 } else {
898 rc = action_exec_helper(op);
899 }
900 crm_trace(" > " PCMK__OP_FMT ": %s = %d",
901 op->rsc, op->action, op->interval_ms, op->opaque->exec, op->rc);
902 if (op->stdout_data) {
903 crm_trace(" > stdout: %s", op->stdout_data);
904 }
905 if (op->stderr_data) {
906 crm_trace(" > stderr: %s", op->stderr_data);
907 }
908 return rc;
909 }
910
911 GList *
912 get_directory_list(const char *root, gboolean files, gboolean executable)
913 {
914 return services_os_get_directory_list(root, files, executable);
915 }
916
917 GList *
918 resources_list_standards(void)
919 {
920 GList *standards = NULL;
921 GList *agents = NULL;
922
923 standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_OCF));
924 standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_LSB));
925 standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_SERVICE));
926
927 #if SUPPORT_SYSTEMD
928 agents = systemd_unit_listall();
929 if (agents) {
930 standards = g_list_append(standards,
931 strdup(PCMK_RESOURCE_CLASS_SYSTEMD));
932 g_list_free_full(agents, free);
933 }
934 #endif
935
936 #if SUPPORT_UPSTART
937 agents = upstart_job_listall();
938 if (agents) {
939 standards = g_list_append(standards,
940 strdup(PCMK_RESOURCE_CLASS_UPSTART));
941 g_list_free_full(agents, free);
942 }
943 #endif
944
945 #if SUPPORT_NAGIOS
946 agents = services__list_nagios_agents();
947 if (agents) {
948 standards = g_list_append(standards,
949 strdup(PCMK_RESOURCE_CLASS_NAGIOS));
950 g_list_free_full(agents, free);
951 }
952 #endif
953
954 return standards;
955 }
956
957 GList *
958 resources_list_providers(const char *standard)
959 {
960 if (pcmk_is_set(pcmk_get_ra_caps(standard), pcmk_ra_cap_provider)) {
961 return resources_os_list_ocf_providers();
962 }
963
964 return NULL;
965 }
966
967 GList *
968 resources_list_agents(const char *standard, const char *provider)
969 {
970 if ((standard == NULL)
971 || (strcasecmp(standard, PCMK_RESOURCE_CLASS_SERVICE) == 0)) {
972
973 GList *tmp1;
974 GList *tmp2;
975 GList *result = services__list_lsb_agents();
976
977 if (standard == NULL) {
978 tmp1 = result;
979 tmp2 = resources_os_list_ocf_agents(NULL);
980 if (tmp2) {
981 result = g_list_concat(tmp1, tmp2);
982 }
983 }
984 #if SUPPORT_SYSTEMD
985 tmp1 = result;
986 tmp2 = systemd_unit_listall();
987 if (tmp2) {
988 result = g_list_concat(tmp1, tmp2);
989 }
990 #endif
991
992 #if SUPPORT_UPSTART
993 tmp1 = result;
994 tmp2 = upstart_job_listall();
995 if (tmp2) {
996 result = g_list_concat(tmp1, tmp2);
997 }
998 #endif
999
1000 return result;
1001
1002 } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_OCF) == 0) {
1003 return resources_os_list_ocf_agents(provider);
1004 } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_LSB) == 0) {
1005 return services__list_lsb_agents();
1006 #if SUPPORT_SYSTEMD
1007 } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_SYSTEMD) == 0) {
1008 return systemd_unit_listall();
1009 #endif
1010 #if SUPPORT_UPSTART
1011 } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_UPSTART) == 0) {
1012 return upstart_job_listall();
1013 #endif
1014 #if SUPPORT_NAGIOS
1015 } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_NAGIOS) == 0) {
1016 return services__list_nagios_agents();
1017 #endif
1018 }
1019
1020 return NULL;
1021 }
1022
1023 gboolean
1024 resources_agent_exists(const char *standard, const char *provider, const char *agent)
1025 {
1026 GList *standards = NULL;
1027 GList *providers = NULL;
1028 GListPtr iter = NULL;
1029 gboolean rc = FALSE;
1030 gboolean has_providers = FALSE;
1031
1032 standards = resources_list_standards();
1033 for (iter = standards; iter != NULL; iter = iter->next) {
1034 if (pcmk__str_eq(iter->data, standard, pcmk__str_none)) {
1035 rc = TRUE;
1036 break;
1037 }
1038 }
1039
1040 if (rc == FALSE) {
1041 goto done;
1042 }
1043
1044 rc = FALSE;
1045
1046 has_providers = pcmk_is_set(pcmk_get_ra_caps(standard), pcmk_ra_cap_provider);
1047 if (has_providers == TRUE && provider != NULL) {
1048 providers = resources_list_providers(standard);
1049 for (iter = providers; iter != NULL; iter = iter->next) {
1050 if (pcmk__str_eq(iter->data, provider, pcmk__str_none)) {
1051 rc = TRUE;
1052 break;
1053 }
1054 }
1055 } else if (has_providers == FALSE && provider == NULL) {
1056 rc = TRUE;
1057 }
1058
1059 if (rc == FALSE) {
1060 goto done;
1061 }
1062
1063 if (pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_SERVICE, pcmk__str_casei)) {
1064 if (services__lsb_agent_exists(agent)) {
1065 rc = TRUE;
1066 #if SUPPORT_SYSTEMD
1067 } else if (systemd_unit_exists(agent)) {
1068 rc = TRUE;
1069 #endif
1070
1071 #if SUPPORT_UPSTART
1072 } else if (upstart_job_exists(agent)) {
1073 rc = TRUE;
1074 #endif
1075 } else {
1076 rc = FALSE;
1077 }
1078
1079 } else if (pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_OCF, pcmk__str_casei)) {
1080 rc = services__ocf_agent_exists(provider, agent);
1081
1082 } else if (pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_LSB, pcmk__str_casei)) {
1083 rc = services__lsb_agent_exists(agent);
1084
1085 #if SUPPORT_SYSTEMD
1086 } else if (pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_SYSTEMD, pcmk__str_casei)) {
1087 rc = systemd_unit_exists(agent);
1088 #endif
1089
1090 #if SUPPORT_UPSTART
1091 } else if (pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_UPSTART, pcmk__str_casei)) {
1092 rc = upstart_job_exists(agent);
1093 #endif
1094
1095 #if SUPPORT_NAGIOS
1096 } else if (pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_NAGIOS, pcmk__str_casei)) {
1097 rc = services__nagios_agent_exists(agent);
1098 #endif
1099
1100 } else {
1101 rc = FALSE;
1102 }
1103
1104 done:
1105 g_list_free(standards);
1106 g_list_free(providers);
1107 return rc;
1108 }