This source file includes following definitions.
- services__systemd_prepare
- services__systemd2ocf
- systemd_new_method
- systemd_send
- systemd_send_recv
- systemd_call_simple_method
- systemd_init
- systemd_get_property
- systemd_cleanup
- systemd_unit_extension
- systemd_service_name
- systemd_daemon_reload_complete
- systemd_daemon_reload
- set_result_from_method_error
- execute_after_loadunit
- loadunit_completed
- invoke_unit_by_name
- sort_str
- systemd_unit_listall
- systemd_unit_exists
- systemd_unit_metadata
- process_unit_method_reply
- unit_method_complete
- create_world_readable
- create_override_dir
- get_override_filename
- systemd_create_override
- systemd_remove_override
- parse_status_result
- invoke_unit_by_path
- systemd_timeout_callback
- services__execute_systemd
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11 #include <crm/crm.h>
12 #include <crm/services.h>
13 #include <crm/services_internal.h>
14 #include <crm/common/mainloop.h>
15
16 #include <sys/stat.h>
17 #include <gio/gio.h>
18 #include <services_private.h>
19 #include <systemd.h>
20 #include <dbus/dbus.h>
21 #include <pcmk-dbus.h>
22
23 static void invoke_unit_by_path(svc_action_t *op, const char *unit);
24
25 #define BUS_NAME "org.freedesktop.systemd1"
26 #define BUS_NAME_MANAGER BUS_NAME ".Manager"
27 #define BUS_NAME_UNIT BUS_NAME ".Unit"
28 #define BUS_PATH "/org/freedesktop/systemd1"
29
30
31
32
33
34
35
36
37
38 int
39 services__systemd_prepare(svc_action_t *op)
40 {
41 op->opaque->exec = strdup("systemd-dbus");
42 if (op->opaque->exec == NULL) {
43 return ENOMEM;
44 }
45 return pcmk_rc_ok;
46 }
47
48
49
50
51
52
53
54
55
56 enum ocf_exitcode
57 services__systemd2ocf(int exit_status)
58 {
59
60 return (enum ocf_exitcode) exit_status;
61 }
62
63 static inline DBusMessage *
64 systemd_new_method(const char *method)
65 {
66 crm_trace("Calling: %s on " BUS_NAME_MANAGER, method);
67 return dbus_message_new_method_call(BUS_NAME, BUS_PATH, BUS_NAME_MANAGER,
68 method);
69 }
70
71
72
73
74
75 static DBusConnection* systemd_proxy = NULL;
76
77 static inline DBusPendingCall *
78 systemd_send(DBusMessage *msg,
79 void(*done)(DBusPendingCall *pending, void *user_data),
80 void *user_data, int timeout)
81 {
82 return pcmk_dbus_send(msg, systemd_proxy, done, user_data, timeout);
83 }
84
85 static inline DBusMessage *
86 systemd_send_recv(DBusMessage *msg, DBusError *error, int timeout)
87 {
88 return pcmk_dbus_send_recv(msg, systemd_proxy, error, timeout);
89 }
90
91
92
93
94
95
96
97
98
99
100
101
102 static DBusMessage *
103 systemd_call_simple_method(const char *method)
104 {
105 DBusMessage *msg = systemd_new_method(method);
106 DBusMessage *reply = NULL;
107 DBusError error;
108
109
110 CRM_CHECK(systemd_proxy, return NULL);
111
112 if (msg == NULL) {
113 crm_err("Could not create message to send %s to systemd", method);
114 return NULL;
115 }
116
117 dbus_error_init(&error);
118 reply = systemd_send_recv(msg, &error, DBUS_TIMEOUT_USE_DEFAULT);
119 dbus_message_unref(msg);
120
121 if (dbus_error_is_set(&error)) {
122 crm_err("Could not send %s to systemd: %s (%s)",
123 method, error.message, error.name);
124 dbus_error_free(&error);
125 return NULL;
126
127 } else if (reply == NULL) {
128 crm_err("Could not send %s to systemd: no reply received", method);
129 return NULL;
130 }
131
132 return reply;
133 }
134
135 static gboolean
136 systemd_init(void)
137 {
138 static int need_init = 1;
139
140
141 if (systemd_proxy
142 && dbus_connection_get_is_connected(systemd_proxy) == FALSE) {
143 crm_warn("Connection to System DBus is closed. Reconnecting...");
144 pcmk_dbus_disconnect(systemd_proxy);
145 systemd_proxy = NULL;
146 need_init = 1;
147 }
148
149 if (need_init) {
150 need_init = 0;
151 systemd_proxy = pcmk_dbus_connect();
152 }
153 if (systemd_proxy == NULL) {
154 return FALSE;
155 }
156 return TRUE;
157 }
158
159 static inline char *
160 systemd_get_property(const char *unit, const char *name,
161 void (*callback)(const char *name, const char *value, void *userdata),
162 void *userdata, DBusPendingCall **pending, int timeout)
163 {
164 return systemd_proxy?
165 pcmk_dbus_get_property(systemd_proxy, BUS_NAME, unit, BUS_NAME_UNIT,
166 name, callback, userdata, pending, timeout)
167 : NULL;
168 }
169
170 void
171 systemd_cleanup(void)
172 {
173 if (systemd_proxy) {
174 pcmk_dbus_disconnect(systemd_proxy);
175 systemd_proxy = NULL;
176 }
177 }
178
179
180
181
182
183
184
185
186
187
188
189
190
191 static const char *
192 systemd_unit_extension(const char *name)
193 {
194 if (name) {
195 const char *dot = strrchr(name, '.');
196
197 if (dot && (!strcmp(dot, ".service")
198 || !strcmp(dot, ".socket")
199 || !strcmp(dot, ".mount")
200 || !strcmp(dot, ".timer")
201 || !strcmp(dot, ".path"))) {
202 return dot;
203 }
204 }
205 return NULL;
206 }
207
208 static char *
209 systemd_service_name(const char *name)
210 {
211 if (name == NULL) {
212 return NULL;
213 }
214
215 if (systemd_unit_extension(name)) {
216 return strdup(name);
217 }
218
219 return crm_strdup_printf("%s.service", name);
220 }
221
222 static void
223 systemd_daemon_reload_complete(DBusPendingCall *pending, void *user_data)
224 {
225 DBusError error;
226 DBusMessage *reply = NULL;
227 unsigned int reload_count = GPOINTER_TO_UINT(user_data);
228
229 dbus_error_init(&error);
230 if(pending) {
231 reply = dbus_pending_call_steal_reply(pending);
232 }
233
234 if (pcmk_dbus_find_error(pending, reply, &error)) {
235 crm_err("Could not issue systemd reload %d: %s", reload_count, error.message);
236 dbus_error_free(&error);
237
238 } else {
239 crm_trace("Reload %d complete", reload_count);
240 }
241
242 if(pending) {
243 dbus_pending_call_unref(pending);
244 }
245 if(reply) {
246 dbus_message_unref(reply);
247 }
248 }
249
250 static bool
251 systemd_daemon_reload(int timeout)
252 {
253 static unsigned int reload_count = 0;
254 DBusMessage *msg = systemd_new_method("Reload");
255
256 reload_count++;
257 CRM_ASSERT(msg != NULL);
258 systemd_send(msg, systemd_daemon_reload_complete,
259 GUINT_TO_POINTER(reload_count), timeout);
260 dbus_message_unref(msg);
261
262 return TRUE;
263 }
264
265
266
267
268
269
270
271
272 static void
273 set_result_from_method_error(svc_action_t *op, const DBusError *error)
274 {
275 services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
276 "Unable to invoke systemd DBus method");
277
278 if (strstr(error->name, "org.freedesktop.systemd1.InvalidName")
279 || strstr(error->name, "org.freedesktop.systemd1.LoadFailed")
280 || strstr(error->name, "org.freedesktop.systemd1.NoSuchUnit")) {
281
282 if (pcmk__str_eq(op->action, "stop", pcmk__str_casei)) {
283 crm_trace("Masking systemd stop failure (%s) for %s "
284 "because unknown service can be considered stopped",
285 error->name, crm_str(op->rsc));
286 services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
287 return;
288 }
289
290 services__set_result(op, PCMK_OCF_NOT_INSTALLED,
291 PCMK_EXEC_NOT_INSTALLED, "systemd unit not found");
292 }
293
294 crm_err("DBus request for %s of systemd unit %s for resource %s failed: %s",
295 op->action, op->agent, crm_str(op->rsc), error->message);
296 }
297
298
299
300
301
302
303
304
305
306
307
308 static const char *
309 execute_after_loadunit(DBusMessage *reply, svc_action_t *op)
310 {
311 const char *path = NULL;
312 DBusError error;
313
314
315
316
317 if (pcmk_dbus_find_error((void *) &path, reply, &error)) {
318 if (op != NULL) {
319 set_result_from_method_error(op, &error);
320 }
321 dbus_error_free(&error);
322
323 } else if (!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH,
324 __func__, __LINE__)) {
325 if (op != NULL) {
326 services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
327 "systemd DBus method had unexpected reply");
328 crm_err("Could not load systemd unit %s for %s: "
329 "DBus reply has unexpected type", op->agent, op->id);
330 } else {
331 crm_err("Could not load systemd unit: "
332 "DBus reply has unexpected type");
333 }
334
335 } else {
336 dbus_message_get_args (reply, NULL,
337 DBUS_TYPE_OBJECT_PATH, &path,
338 DBUS_TYPE_INVALID);
339 }
340
341 if (op != NULL) {
342 if (path != NULL) {
343 invoke_unit_by_path(op, path);
344
345 } else if (!(op->synchronous)) {
346 services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
347 "No DBus object found for systemd unit");
348 services__finalize_async_op(op);
349 }
350 }
351
352 return path;
353 }
354
355
356
357
358
359
360
361
362 static void
363 loadunit_completed(DBusPendingCall *pending, void *user_data)
364 {
365 DBusMessage *reply = NULL;
366 svc_action_t *op = user_data;
367
368 crm_trace("LoadUnit result for %s arrived", op->id);
369
370
371 if (pending != NULL) {
372 reply = dbus_pending_call_steal_reply(pending);
373 }
374
375
376 CRM_LOG_ASSERT(pending == op->opaque->pending);
377 services_set_op_pending(op, NULL);
378
379
380 execute_after_loadunit(reply, user_data);
381 if (reply != NULL) {
382 dbus_message_unref(reply);
383 }
384 }
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401 static int
402 invoke_unit_by_name(const char *arg_name, svc_action_t *op, char **path)
403 {
404 DBusMessage *msg;
405 DBusMessage *reply = NULL;
406 DBusPendingCall *pending = NULL;
407 char *name = NULL;
408
409 if (!systemd_init()) {
410 if (op != NULL) {
411 services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
412 "No DBus connection");
413 }
414 return ENOTCONN;
415 }
416
417
418
419
420
421
422
423
424
425 msg = systemd_new_method("LoadUnit");
426 CRM_ASSERT(msg != NULL);
427
428
429 name = systemd_service_name(arg_name);
430 CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name,
431 DBUS_TYPE_INVALID));
432 free(name);
433
434 if ((op == NULL) || op->synchronous) {
435
436 const char *unit = NULL;
437 int rc = pcmk_rc_ok;
438
439 reply = systemd_send_recv(msg, NULL,
440 (op? op->timeout : DBUS_TIMEOUT_USE_DEFAULT));
441 dbus_message_unref(msg);
442
443 unit = execute_after_loadunit(reply, op);
444 if (unit == NULL) {
445 rc = ENOENT;
446 if (path != NULL) {
447 *path = NULL;
448 }
449 } else if (path != NULL) {
450 *path = strdup(unit);
451 if (*path == NULL) {
452 rc = ENOMEM;
453 }
454 }
455
456 if (reply != NULL) {
457 dbus_message_unref(reply);
458 }
459 return rc;
460 }
461
462
463 pending = systemd_send(msg, loadunit_completed, op, op->timeout);
464 if (pending == NULL) {
465 services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
466 "Unable to send DBus message");
467 dbus_message_unref(msg);
468 return ECOMM;
469 }
470
471
472 services__set_result(op, PCMK_OCF_UNKNOWN, PCMK_EXEC_PENDING, NULL);
473 services_set_op_pending(op, pending);
474 dbus_message_unref(msg);
475 return pcmk_rc_ok;
476 }
477
478
479
480
481
482
483
484
485
486
487
488
489
490 static gint
491 sort_str(gconstpointer a, gconstpointer b)
492 {
493 if (!a && !b) {
494 return 0;
495 } else if (!a) {
496 return -1;
497 } else if (!b) {
498 return 1;
499 }
500 return strcasecmp(a, b);
501 }
502
503 GList *
504 systemd_unit_listall(void)
505 {
506 int nfiles = 0;
507 GList *units = NULL;
508 DBusMessageIter args;
509 DBusMessageIter unit;
510 DBusMessageIter elem;
511 DBusMessage *reply = NULL;
512
513 if (systemd_init() == FALSE) {
514 return NULL;
515 }
516
517
518
519
520
521
522
523 reply = systemd_call_simple_method("ListUnitFiles");
524 if (reply == NULL) {
525 return NULL;
526 }
527 if (!dbus_message_iter_init(reply, &args)) {
528 crm_err("Could not list systemd unit files: systemd reply has no arguments");
529 dbus_message_unref(reply);
530 return NULL;
531 }
532 if (!pcmk_dbus_type_check(reply, &args, DBUS_TYPE_ARRAY,
533 __func__, __LINE__)) {
534 crm_err("Could not list systemd unit files: systemd reply has invalid arguments");
535 dbus_message_unref(reply);
536 return NULL;
537 }
538
539 dbus_message_iter_recurse(&args, &unit);
540 for (; dbus_message_iter_get_arg_type(&unit) != DBUS_TYPE_INVALID;
541 dbus_message_iter_next(&unit)) {
542
543 DBusBasicValue value;
544 const char *match = NULL;
545 char *unit_name = NULL;
546 char *basename = NULL;
547
548 if(!pcmk_dbus_type_check(reply, &unit, DBUS_TYPE_STRUCT, __func__, __LINE__)) {
549 crm_warn("Skipping systemd reply argument with unexpected type");
550 continue;
551 }
552
553 dbus_message_iter_recurse(&unit, &elem);
554 if(!pcmk_dbus_type_check(reply, &elem, DBUS_TYPE_STRING, __func__, __LINE__)) {
555 crm_warn("Skipping systemd reply argument with no string");
556 continue;
557 }
558
559 dbus_message_iter_get_basic(&elem, &value);
560 if (value.str == NULL) {
561 crm_debug("ListUnitFiles reply did not provide a string");
562 continue;
563 }
564 crm_trace("DBus ListUnitFiles listed: %s", value.str);
565
566 match = systemd_unit_extension(value.str);
567 if (match == NULL) {
568
569 crm_debug("ListUnitFiles entry '%s' is not supported as resource",
570 value.str);
571 continue;
572 }
573
574
575 basename = strrchr(value.str, '/');
576 if (basename) {
577 basename = basename + 1;
578 } else {
579 basename = value.str;
580 }
581
582 if (!strcmp(match, ".service")) {
583
584 unit_name = strndup(basename, match - basename);
585 } else {
586 unit_name = strdup(basename);
587 }
588
589 nfiles++;
590 units = g_list_prepend(units, unit_name);
591 }
592
593 dbus_message_unref(reply);
594
595 crm_trace("Found %d manageable systemd unit files", nfiles);
596 units = g_list_sort(units, sort_str);
597 return units;
598 }
599
600 gboolean
601 systemd_unit_exists(const char *name)
602 {
603 char *path = NULL;
604 char *state = NULL;
605
606
607
608
609 if ((invoke_unit_by_name(name, NULL, &path) != pcmk_rc_ok)
610 || (path == NULL)) {
611 return FALSE;
612 }
613
614
615
616
617
618 state = systemd_get_property(path, "LoadState", NULL, NULL, NULL,
619 DBUS_TIMEOUT_USE_DEFAULT);
620 free(path);
621 if (pcmk__str_any_of(state, "loaded", "masked", NULL)) {
622 free(state);
623 return TRUE;
624 }
625 free(state);
626 return FALSE;
627 }
628
629 #define METADATA_FORMAT \
630 "<?xml version=\"1.0\"?>\n" \
631 "<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n" \
632 "<resource-agent name=\"%s\" version=\"" PCMK_DEFAULT_AGENT_VERSION "\">\n" \
633 " <version>1.1</version>\n" \
634 " <longdesc lang=\"en\">\n" \
635 " %s\n" \
636 " </longdesc>\n" \
637 " <shortdesc lang=\"en\">systemd unit file for %s</shortdesc>\n" \
638 " <parameters/>\n" \
639 " <actions>\n" \
640 " <action name=\"start\" timeout=\"100\" />\n" \
641 " <action name=\"stop\" timeout=\"100\" />\n" \
642 " <action name=\"status\" timeout=\"100\" />\n" \
643 " <action name=\"monitor\" timeout=\"100\" interval=\"60\"/>\n" \
644 " <action name=\"meta-data\" timeout=\"5\" />\n" \
645 " </actions>\n" \
646 " <special tag=\"systemd\"/>\n" \
647 "</resource-agent>\n"
648
649 static char *
650 systemd_unit_metadata(const char *name, int timeout)
651 {
652 char *meta = NULL;
653 char *desc = NULL;
654 char *path = NULL;
655
656 if (invoke_unit_by_name(name, NULL, &path) == pcmk_rc_ok) {
657
658 desc = systemd_get_property(path, "Description", NULL, NULL, NULL,
659 timeout);
660 } else {
661 desc = crm_strdup_printf("Systemd unit file for %s", name);
662 }
663
664 meta = crm_strdup_printf(METADATA_FORMAT, name, desc, name);
665 free(desc);
666 free(path);
667 return meta;
668 }
669
670
671
672
673
674
675
676
677 static void
678 process_unit_method_reply(DBusMessage *reply, svc_action_t *op)
679 {
680 DBusError error;
681
682
683
684
685 if (pcmk_dbus_find_error((void *) &error, reply, &error)) {
686 set_result_from_method_error(op, &error);
687 dbus_error_free(&error);
688
689 } else if (!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH,
690 __func__, __LINE__)) {
691 crm_warn("DBus request for %s of %s succeeded but "
692 "return type was unexpected", op->action, crm_str(op->rsc));
693 services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE,
694 "systemd DBus method had unexpected reply");
695
696 } else {
697 const char *path = NULL;
698
699 dbus_message_get_args(reply, NULL,
700 DBUS_TYPE_OBJECT_PATH, &path,
701 DBUS_TYPE_INVALID);
702 crm_debug("DBus request for %s of %s using %s succeeded",
703 op->action, crm_str(op->rsc), path);
704 services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
705 }
706 }
707
708
709
710
711
712
713
714
715 static void
716 unit_method_complete(DBusPendingCall *pending, void *user_data)
717 {
718 DBusMessage *reply = NULL;
719 svc_action_t *op = user_data;
720
721 crm_trace("Result for %s arrived", op->id);
722
723
724 if (pending != NULL) {
725 reply = dbus_pending_call_steal_reply(pending);
726 }
727
728
729 CRM_LOG_ASSERT(pending == op->opaque->pending);
730 services_set_op_pending(op, NULL);
731
732
733 process_unit_method_reply(reply, op);
734 services__finalize_async_op(op);
735 if (reply != NULL) {
736 dbus_message_unref(reply);
737 }
738 }
739
740 #define SYSTEMD_OVERRIDE_ROOT "/run/systemd/system/"
741
742
743
744
745
746
747
748
749
750
751 #define SYSTEMD_OVERRIDE_TEMPLATE \
752 "[Unit]\n" \
753 "Description=Cluster Controlled %s\n" \
754 "Before=pacemaker.service pacemaker_remote.service\n" \
755 "\n" \
756 "[Service]\n" \
757 "Restart=no\n"
758
759
760 static FILE *
761 create_world_readable(const char *filename)
762 {
763 mode_t orig_umask = umask(S_IWGRP | S_IWOTH);
764 FILE *fp = fopen(filename, "w");
765
766 umask(orig_umask);
767 return fp;
768 }
769
770 static void
771 create_override_dir(const char *agent)
772 {
773 char *override_dir = crm_strdup_printf(SYSTEMD_OVERRIDE_ROOT
774 "/%s.service.d", agent);
775 int rc = pcmk__build_path(override_dir, 0755);
776
777 if (rc != pcmk_rc_ok) {
778 crm_warn("Could not create systemd override directory %s: %s",
779 override_dir, pcmk_rc_str(rc));
780 }
781 free(override_dir);
782 }
783
784 static char *
785 get_override_filename(const char *agent)
786 {
787 return crm_strdup_printf(SYSTEMD_OVERRIDE_ROOT
788 "/%s.service.d/50-pacemaker.conf", agent);
789 }
790
791 static void
792 systemd_create_override(const char *agent, int timeout)
793 {
794 FILE *file_strm = NULL;
795 char *override_file = get_override_filename(agent);
796
797 create_override_dir(agent);
798
799
800
801
802 file_strm = create_world_readable(override_file);
803 if (file_strm == NULL) {
804 crm_err("Cannot open systemd override file %s for writing",
805 override_file);
806 } else {
807 char *override = crm_strdup_printf(SYSTEMD_OVERRIDE_TEMPLATE, agent);
808
809 int rc = fprintf(file_strm, "%s\n", override);
810
811 free(override);
812 if (rc < 0) {
813 crm_perror(LOG_WARNING, "Cannot write to systemd override file %s",
814 override_file);
815 }
816 fflush(file_strm);
817 fclose(file_strm);
818 systemd_daemon_reload(timeout);
819 }
820
821 free(override_file);
822 }
823
824 static void
825 systemd_remove_override(const char *agent, int timeout)
826 {
827 char *override_file = get_override_filename(agent);
828 int rc = unlink(override_file);
829
830 if (rc < 0) {
831
832 crm_perror(LOG_DEBUG, "Cannot remove systemd override file %s",
833 override_file);
834 } else {
835 systemd_daemon_reload(timeout);
836 }
837 free(override_file);
838 }
839
840
841
842
843
844
845
846
847
848
849
850
851 static void
852 parse_status_result(const char *name, const char *state, void *userdata)
853 {
854 svc_action_t *op = userdata;
855
856 crm_trace("Resource %s has %s='%s'",
857 crm_str(op->rsc), name, crm_str(state));
858
859 if (pcmk__str_eq(state, "active", pcmk__str_none)) {
860 services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
861
862 } else if (pcmk__str_eq(state, "reloading", pcmk__str_none)) {
863 services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
864
865 } else if (pcmk__str_eq(state, "activating", pcmk__str_none)) {
866 services__set_result(op, PCMK_OCF_UNKNOWN, PCMK_EXEC_PENDING, NULL);
867
868 } else if (pcmk__str_eq(state, "deactivating", pcmk__str_none)) {
869 services__set_result(op, PCMK_OCF_UNKNOWN, PCMK_EXEC_PENDING, NULL);
870
871 } else {
872 services__set_result(op, PCMK_OCF_NOT_RUNNING, PCMK_EXEC_DONE, state);
873 }
874
875 if (!(op->synchronous)) {
876 services_set_op_pending(op, NULL);
877 services__finalize_async_op(op);
878 }
879 }
880
881
882
883
884
885
886
887
888 static void
889 invoke_unit_by_path(svc_action_t *op, const char *unit)
890 {
891 const char *method = NULL;
892 DBusMessage *msg = NULL;
893 DBusMessage *reply = NULL;
894
895 if (pcmk__str_any_of(op->action, "monitor", "status", NULL)) {
896 DBusPendingCall *pending = NULL;
897 char *state;
898
899 state = systemd_get_property(unit, "ActiveState",
900 (op->synchronous? NULL : parse_status_result),
901 op, (op->synchronous? NULL : &pending),
902 op->timeout);
903 if (op->synchronous) {
904 parse_status_result("ActiveState", state, op);
905 free(state);
906
907 } else if (pending == NULL) {
908 services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
909 "Could not get unit state from DBus");
910 services__finalize_async_op(op);
911
912 } else {
913 services_set_op_pending(op, pending);
914 }
915 return;
916
917 } else if (pcmk__str_eq(op->action, "start", pcmk__str_none)) {
918 method = "StartUnit";
919 systemd_create_override(op->agent, op->timeout);
920
921 } else if (pcmk__str_eq(op->action, "stop", pcmk__str_none)) {
922 method = "StopUnit";
923 systemd_remove_override(op->agent, op->timeout);
924
925 } else if (pcmk__str_eq(op->action, "restart", pcmk__str_none)) {
926 method = "RestartUnit";
927
928 } else {
929 services__set_result(op, PCMK_OCF_UNIMPLEMENT_FEATURE, PCMK_EXEC_ERROR,
930 "Action not implemented for systemd resources");
931 if (!(op->synchronous)) {
932 services__finalize_async_op(op);
933 }
934 return;
935 }
936
937 crm_trace("Calling %s for unit path %s named %s",
938 method, unit, crm_str(op->rsc));
939
940 msg = systemd_new_method(method);
941 CRM_ASSERT(msg != NULL);
942
943
944 {
945 const char *replace_s = "replace";
946 char *name = systemd_service_name(op->agent);
947
948 CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID));
949 CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &replace_s, DBUS_TYPE_INVALID));
950
951 free(name);
952 }
953
954 if (op->synchronous) {
955 reply = systemd_send_recv(msg, NULL, op->timeout);
956 dbus_message_unref(msg);
957 process_unit_method_reply(reply, op);
958 if (reply != NULL) {
959 dbus_message_unref(reply);
960 }
961
962 } else {
963 DBusPendingCall *pending = systemd_send(msg, unit_method_complete, op,
964 op->timeout);
965
966 dbus_message_unref(msg);
967 if (pending == NULL) {
968 services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
969 "Unable to send DBus message");
970 services__finalize_async_op(op);
971
972 } else {
973 services_set_op_pending(op, pending);
974 }
975 }
976 }
977
978 static gboolean
979 systemd_timeout_callback(gpointer p)
980 {
981 svc_action_t * op = p;
982
983 op->opaque->timerid = 0;
984 crm_warn("%s operation on systemd unit %s named '%s' timed out", op->action, op->agent, op->rsc);
985 services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_TIMEOUT,
986 "Systemd action did not complete within specified timeout");
987 services__finalize_async_op(op);
988 return FALSE;
989 }
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007 int
1008 services__execute_systemd(svc_action_t *op)
1009 {
1010 CRM_ASSERT(op != NULL);
1011
1012 if ((op->action == NULL) || (op->agent == NULL)) {
1013 services__set_result(op, PCMK_OCF_NOT_CONFIGURED, PCMK_EXEC_ERROR_FATAL,
1014 "Bug in action caller");
1015 goto done;
1016 }
1017
1018 if (!systemd_init()) {
1019 services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
1020 "No DBus connection");
1021 goto done;
1022 }
1023
1024 crm_debug("Performing %ssynchronous %s op on systemd unit %s named '%s'",
1025 (op->synchronous? "" : "a"), op->action, op->agent,
1026 crm_str(op->rsc));
1027
1028 if (pcmk__str_eq(op->action, "meta-data", pcmk__str_casei)) {
1029 op->stdout_data = systemd_unit_metadata(op->agent, op->timeout);
1030 services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
1031 goto done;
1032 }
1033
1034
1035
1036
1037 services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
1038 "Bug in service library");
1039
1040 if (invoke_unit_by_name(op->agent, op, NULL) == pcmk_rc_ok) {
1041 op->opaque->timerid = g_timeout_add(op->timeout + 5000,
1042 systemd_timeout_callback, op);
1043 services_add_inflight_op(op);
1044 return pcmk_rc_ok;
1045 }
1046
1047 done:
1048 if (op->synchronous) {
1049 return (op->rc == PCMK_OCF_OK)? pcmk_rc_ok : pcmk_rc_error;
1050 } else {
1051 return services__finalize_async_op(op);
1052 }
1053 }