21 #include <dbus/dbus.h> 24 static void invoke_unit_by_path(
svc_action_t *op,
const char *unit);
26 #define BUS_NAME "org.freedesktop.systemd1" 27 #define BUS_NAME_MANAGER BUS_NAME ".Manager" 28 #define BUS_NAME_UNIT BUS_NAME ".Unit" 29 #define BUS_PATH "/org/freedesktop/systemd1" 64 static inline DBusMessage *
65 systemd_new_method(
const char *method)
76 static DBusConnection* systemd_proxy = NULL;
78 static inline DBusPendingCall *
79 systemd_send(DBusMessage *msg,
80 void(*done)(DBusPendingCall *pending,
void *user_data),
86 static inline DBusMessage *
87 systemd_send_recv(DBusMessage *msg, DBusError *error,
int timeout)
104 systemd_call_simple_method(
const char *method)
106 DBusMessage *msg = systemd_new_method(method);
107 DBusMessage *reply = NULL;
114 crm_err(
"Could not create message to send %s to systemd", method);
118 dbus_error_init(&error);
120 dbus_message_unref(msg);
122 if (dbus_error_is_set(&error)) {
123 crm_err(
"Could not send %s to systemd: %s (%s)",
124 method, error.message, error.name);
125 dbus_error_free(&error);
128 }
else if (reply == NULL) {
129 crm_err(
"Could not send %s to systemd: no reply received", method);
139 static int need_init = 1;
143 && dbus_connection_get_is_connected(systemd_proxy) == FALSE) {
144 crm_warn(
"Connection to System DBus is closed. Reconnecting...");
146 systemd_proxy = NULL;
154 if (systemd_proxy == NULL) {
161 systemd_get_property(
const char *unit,
const char *
name,
162 void (*callback)(
const char *
name,
const char *value,
void *userdata),
163 void *userdata, DBusPendingCall **pending,
int timeout)
165 return systemd_proxy?
176 systemd_proxy = NULL;
193 systemd_unit_extension(
const char *
name)
196 const char *dot = strrchr(
name,
'.');
198 if (dot && (!strcmp(dot,
".service")
199 || !strcmp(dot,
".socket")
200 || !strcmp(dot,
".mount")
201 || !strcmp(dot,
".timer")
202 || !strcmp(dot,
".path"))) {
210 systemd_service_name(
const char *
name,
bool add_instance_name)
212 const char *dot = NULL;
214 if (pcmk__str_empty(
name)) {
227 dot = systemd_unit_extension(
name);
230 if (dot !=
name && *(dot-1) ==
'@') {
233 if (asprintf(&s,
"%.*spacemaker%s", (
int) (dot-
name),
name, dot) == -1) {
243 }
else if (add_instance_name && *(
name+strlen(
name)-1) ==
'@') {
252 systemd_daemon_reload_complete(DBusPendingCall *pending,
void *user_data)
255 DBusMessage *reply = NULL;
256 unsigned int reload_count = GPOINTER_TO_UINT(user_data);
258 dbus_error_init(&error);
260 reply = dbus_pending_call_steal_reply(pending);
264 crm_warn(
"Could not issue systemd reload %d: %s",
265 reload_count, error.message);
266 dbus_error_free(&error);
269 crm_trace(
"Reload %d complete", reload_count);
273 dbus_pending_call_unref(pending);
276 dbus_message_unref(reply);
281 systemd_daemon_reload(
int timeout)
283 static unsigned int reload_count = 0;
284 DBusMessage *msg = systemd_new_method(
"Reload");
288 systemd_send(msg, systemd_daemon_reload_complete,
289 GUINT_TO_POINTER(reload_count),
timeout);
290 dbus_message_unref(msg);
303 set_result_from_method_error(
svc_action_t *op,
const DBusError *error)
306 "Unable to invoke systemd DBus method");
308 if (strstr(error->name,
"org.freedesktop.systemd1.InvalidName")
309 || strstr(error->name,
"org.freedesktop.systemd1.LoadFailed")
310 || strstr(error->name,
"org.freedesktop.systemd1.NoSuchUnit")) {
313 crm_trace(
"Masking systemd stop failure (%s) for %s " 314 "because unknown service can be considered stopped",
315 error->name, pcmk__s(op->
rsc,
"unknown resource"));
322 "systemd unit %s not found", op->
agent);
325 crm_info(
"DBus request for %s of systemd unit %s%s%s failed: %s",
327 ((op->
rsc == NULL)?
"" :
" for resource "), pcmk__s(op->
rsc,
""),
342 execute_after_loadunit(DBusMessage *reply,
svc_action_t *op)
344 const char *
path = NULL;
352 set_result_from_method_error(op, &error);
354 dbus_error_free(&error);
357 __func__, __LINE__)) {
360 "systemd DBus method had unexpected reply");
361 crm_info(
"Could not load systemd unit %s for %s: " 362 "DBus reply has unexpected type", op->
agent, op->
id);
364 crm_info(
"Could not load systemd unit: " 365 "DBus reply has unexpected type");
369 dbus_message_get_args (reply, NULL,
370 DBUS_TYPE_OBJECT_PATH, &
path,
376 invoke_unit_by_path(op,
path);
380 "No DBus object found for systemd unit %s",
397 loadunit_completed(DBusPendingCall *pending,
void *user_data)
399 DBusMessage *reply = NULL;
402 crm_trace(
"LoadUnit result for %s arrived", op->
id);
405 if (pending != NULL) {
406 reply = dbus_pending_call_steal_reply(pending);
411 services_set_op_pending(op, NULL);
414 execute_after_loadunit(reply, user_data);
416 dbus_message_unref(reply);
439 DBusMessage *reply = NULL;
440 DBusPendingCall *pending = NULL;
443 if (!systemd_init()) {
446 "No DBus connection");
459 msg = systemd_new_method(
"LoadUnit");
463 name = systemd_service_name(arg_name,
465 || pcmk__str_eq(op->
action,
474 const char *unit = NULL;
477 reply = systemd_send_recv(msg, NULL,
479 dbus_message_unref(msg);
481 unit = execute_after_loadunit(reply, op);
487 }
else if (
path != NULL) {
488 *
path = strdup(unit);
495 dbus_message_unref(reply);
501 pending = systemd_send(msg, loadunit_completed, op, op->
timeout);
502 if (pending == NULL) {
504 "Unable to send DBus message");
505 dbus_message_unref(msg);
511 services_set_op_pending(op, pending);
512 dbus_message_unref(msg);
529 sort_str(gconstpointer a, gconstpointer b)
538 return strcasecmp(a, b);
546 DBusMessageIter args;
547 DBusMessageIter unit;
548 DBusMessageIter elem;
549 DBusMessage *reply = NULL;
551 if (systemd_init() == FALSE) {
561 reply = systemd_call_simple_method(
"ListUnitFiles");
565 if (!dbus_message_iter_init(reply, &args)) {
566 crm_err(
"Could not list systemd unit files: systemd reply has no arguments");
567 dbus_message_unref(reply);
571 __func__, __LINE__)) {
572 crm_err(
"Could not list systemd unit files: systemd reply has invalid arguments");
573 dbus_message_unref(reply);
577 dbus_message_iter_recurse(&args, &unit);
578 for (; dbus_message_iter_get_arg_type(&unit) != DBUS_TYPE_INVALID;
579 dbus_message_iter_next(&unit)) {
581 DBusBasicValue value;
582 const char *match = NULL;
583 char *unit_name = NULL;
584 char *basename = NULL;
587 crm_warn(
"Skipping systemd reply argument with unexpected type");
591 dbus_message_iter_recurse(&unit, &elem);
593 crm_warn(
"Skipping systemd reply argument with no string");
597 dbus_message_iter_get_basic(&elem, &value);
598 if (value.str == NULL) {
599 crm_debug(
"ListUnitFiles reply did not provide a string");
602 crm_trace(
"DBus ListUnitFiles listed: %s", value.str);
604 match = systemd_unit_extension(value.str);
607 crm_debug(
"ListUnitFiles entry '%s' is not supported as resource",
613 basename = strrchr(value.str,
'/');
615 basename = basename + 1;
617 basename = value.str;
620 if (!strcmp(match,
".service")) {
622 unit_name = strndup(basename, match - basename);
624 unit_name = strdup(basename);
628 units = g_list_prepend(units, unit_name);
631 dbus_message_unref(reply);
633 crm_trace(
"Found %d manageable systemd unit files", nfiles);
634 units = g_list_sort(units, sort_str);
656 state = systemd_get_property(
path,
"LoadState", NULL, NULL, NULL,
668 #define METADATA_FORMAT \ 669 "<?xml " PCMK_XA_VERSION "=\"1.0\"?>\n" \ 670 "<" PCMK_XE_RESOURCE_AGENT " " \ 671 PCMK_XA_NAME "=\"%s\" " \ 672 PCMK_XA_VERSION "=\"" PCMK_DEFAULT_AGENT_VERSION "\">\n" \ 673 " <" PCMK_XE_VERSION ">1.1</" PCMK_XE_VERSION ">\n" \ 674 " <" PCMK_XE_LONGDESC " " PCMK_XA_LANG "=\"" PCMK__VALUE_EN "\">\n" \ 676 " </" PCMK_XE_LONGDESC ">\n" \ 677 " <" PCMK_XE_SHORTDESC " " PCMK_XA_LANG "=\"" PCMK__VALUE_EN "\">" \ 678 "systemd unit file for %s" \ 679 "</" PCMK_XE_SHORTDESC ">\n" \ 680 " <" PCMK_XE_PARAMETERS "/>\n" \ 681 " <" PCMK_XE_ACTIONS ">\n" \ 682 " <" PCMK_XE_ACTION " " PCMK_XA_NAME "=\"" PCMK_ACTION_START "\"" \ 683 " " PCMK_META_TIMEOUT "=\"100s\" />\n" \ 684 " <" PCMK_XE_ACTION " " PCMK_XA_NAME "=\"" PCMK_ACTION_STOP "\"" \ 685 " " PCMK_META_TIMEOUT "=\"100s\" />\n" \ 686 " <" PCMK_XE_ACTION " " PCMK_XA_NAME "=\"" PCMK_ACTION_STATUS "\"" \ 687 " " PCMK_META_TIMEOUT "=\"100s\" />\n" \ 688 " <" PCMK_XE_ACTION " " PCMK_XA_NAME "=\"" PCMK_ACTION_MONITOR "\"" \ 689 " " PCMK_META_TIMEOUT "=\"100s\"" \ 690 " " PCMK_META_INTERVAL "=\"60s\" />\n" \ 691 " <" PCMK_XE_ACTION " " PCMK_XA_NAME "=\"" PCMK_ACTION_META_DATA "\"" \ 692 " " PCMK_META_TIMEOUT "=\"5s\" />\n" \ 693 " </" PCMK_XE_ACTIONS ">\n" \ 694 " <" PCMK_XE_SPECIAL " " PCMK_XA_TAG "=\"systemd\"/>\n" \ 695 "</" PCMK_XE_RESOURCE_AGENT ">\n" 698 systemd_unit_metadata(
const char *
name,
int timeout)
706 desc = systemd_get_property(
path,
"Description", NULL, NULL, NULL,
735 process_unit_method_reply(DBusMessage *reply,
svc_action_t *op)
739 dbus_error_init(&error);
745 set_result_from_method_error(op, &error);
746 dbus_error_free(&error);
749 __func__, __LINE__)) {
750 crm_info(
"DBus request for %s of %s succeeded but " 751 "return type was unexpected",
752 op->
action, pcmk__s(op->
rsc,
"unknown resource"));
754 "systemd DBus method had unexpected reply");
757 const char *
path = NULL;
759 dbus_message_get_args(reply, NULL,
760 DBUS_TYPE_OBJECT_PATH, &
path,
762 crm_debug(
"DBus request for %s of %s using %s succeeded",
776 unit_method_complete(DBusPendingCall *pending,
void *user_data)
778 DBusMessage *reply = NULL;
784 if (pending != NULL) {
785 reply = dbus_pending_call_steal_reply(pending);
790 services_set_op_pending(op, NULL);
793 process_unit_method_reply(reply, op);
796 dbus_message_unref(reply);
800 #define SYSTEMD_OVERRIDE_ROOT "/run/systemd/system/" 811 #define SYSTEMD_OVERRIDE_TEMPLATE \ 813 "Description=Cluster Controlled %s\n" \ 814 "Before=pacemaker.service pacemaker_remote.service\n" \ 821 create_world_readable(
const char *filename)
823 mode_t orig_umask = umask(S_IWGRP | S_IWOTH);
824 FILE *fp = fopen(filename,
"w");
831 create_override_dir(
const char *agent)
834 "/%s.service.d", agent);
838 crm_warn(
"Could not create systemd override directory %s: %s",
845 get_override_filename(
const char *agent)
848 "/%s.service.d/50-pacemaker.conf", agent);
852 systemd_create_override(
const char *agent,
int timeout)
854 FILE *file_strm = NULL;
855 char *override_file = get_override_filename(agent);
857 create_override_dir(agent);
862 file_strm = create_world_readable(override_file);
863 if (file_strm == NULL) {
864 crm_err(
"Cannot open systemd override file %s for writing",
869 int rc = fprintf(file_strm,
"%s\n",
override);
873 crm_perror(LOG_WARNING,
"Cannot write to systemd override file %s",
878 systemd_daemon_reload(
timeout);
885 systemd_remove_override(
const char *agent,
int timeout)
887 char *override_file = get_override_filename(agent);
888 int rc = unlink(override_file);
892 crm_perror(LOG_DEBUG,
"Cannot remove systemd override file %s",
895 systemd_daemon_reload(
timeout);
912 parse_status_result(
const char *
name,
const char *state,
void *userdata)
917 pcmk__s(op->
rsc,
"(unspecified)"),
name,
918 pcmk__s(state,
"<null>"));
937 services_set_op_pending(op, NULL);
952 const char *method = NULL;
953 DBusMessage *msg = NULL;
954 DBusMessage *reply = NULL;
958 DBusPendingCall *pending = NULL;
961 state = systemd_get_property(unit,
"ActiveState",
966 parse_status_result(
"ActiveState", state, op);
969 }
else if (pending == NULL) {
971 "Could not get state for unit %s from DBus",
976 services_set_op_pending(op, pending);
981 method =
"StartUnit";
989 method =
"RestartUnit";
994 "Action %s not implemented " 995 "for systemd resources",
996 pcmk__s(op->
action,
"(unspecified)"));
1003 crm_trace(
"Calling %s for unit path %s%s%s",
1005 ((op->
rsc == NULL)?
"" :
" for resource "), pcmk__s(op->
rsc,
""));
1007 msg = systemd_new_method(method);
1012 const char *replace_s =
"replace";
1013 char *
name = systemd_service_name(op->
agent,
1018 CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &
name, DBUS_TYPE_INVALID));
1019 CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &replace_s, DBUS_TYPE_INVALID));
1025 reply = systemd_send_recv(msg, NULL, op->
timeout);
1026 dbus_message_unref(msg);
1027 process_unit_method_reply(reply, op);
1028 if (reply != NULL) {
1029 dbus_message_unref(reply);
1033 DBusPendingCall *pending = systemd_send(msg, unit_method_complete, op,
1036 dbus_message_unref(msg);
1037 if (pending == NULL) {
1039 "Unable to send DBus message");
1043 services_set_op_pending(op, pending);
1049 systemd_timeout_callback(gpointer p)
1054 crm_info(
"%s action for systemd unit %s named '%s' timed out",
1057 "%s action for systemd unit %s " 1058 "did not complete in time", op->
action, op->
agent);
1084 if ((op->
action == NULL) || (op->
agent == NULL)) {
1086 "Bug in action caller");
1090 if (!systemd_init()) {
1092 "No DBus connection");
1096 crm_debug(
"Performing %ssynchronous %s op on systemd unit %s%s%s",
1098 ((op->
rsc == NULL)?
"" :
" for resource "), pcmk__s(op->
rsc,
""));
1110 "Bug in service library");
1114 systemd_timeout_callback, op);
int rc
Exit status of action (set by library upon completion)
#define CRM_CHECK(expr, failure_action)
int services__execute_systemd(svc_action_t *op)
ocf_exitcode
Exit status codes for resource agents.
char * pcmk__xml_escape(const char *text, enum pcmk__xml_escape_type type)
void pcmk_dbus_disconnect(DBusConnection *connection)
bool pcmk__xml_needs_escape(const char *text, enum pcmk__xml_escape_type type)
#define DBUS_TIMEOUT_USE_DEFAULT
#define PCMK_ACTION_META_DATA
#define PCMK_ACTION_MONITOR
char * rsc
XML ID of resource being executed for resource actions, otherwise NULL.
#define CRM_LOG_ASSERT(expr)
int timeout
Action timeout (in milliseconds)
Action did not complete in time.
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Wrappers for and extensions to glib mainloop.
#define PCMK_ACTION_STATUS
#define crm_warn(fmt, args...)
void services__format_result(svc_action_t *action, int agent_status, enum pcmk_exec_status exec_status, const char *format,...) G_GNUC_PRINTF(4
svc_action_private_t * opaque
This field should be treated as internal to Pacemaker.
#define crm_debug(fmt, args...)
char * stdout_data
Action stdout (set by library)
Parameter invalid (inherently)
gboolean systemd_unit_exists(const char *name)
int pcmk__build_path(const char *path_c, mode_t mode)
#define crm_trace(fmt, args...)
int services__finalize_async_op(svc_action_t *op)
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
Object for executing external actions.
#define PCMK_ACTION_START
char * agent
Resource agent name for resource actions, otherwise NULL.
void services__set_result(svc_action_t *action, int agent_status, enum pcmk_exec_status exec_status, const char *exit_reason)
Wrappers for and extensions to libxml2.
Action completed, result is known.
Execution failed, do not retry anywhere.
Dependencies not available locally.
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
#define SYSTEMD_OVERRIDE_ROOT
GList * systemd_unit_listall(void)
DBusPendingCall * pcmk_dbus_send(DBusMessage *msg, DBusConnection *connection, void(*done)(DBusPendingCall *pending, void *user_data), void *user_data, int timeout)
DBusConnection * pcmk_dbus_connect(void)
void services_add_inflight_op(svc_action_t *op)
Requested action not implemented.
int services__systemd_prepare(svc_action_t *op)
void systemd_cleanup(void)
char * action
Name of action being executed for resource actions, otherwise NULL.
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
#define crm_err(fmt, args...)
enum ocf_exitcode services__systemd2ocf(int exit_status)
bool pcmk_dbus_type_check(DBusMessage *msg, DBusMessageIter *field, int expected, const char *function, int line)
Agent or dependency not available locally.
bool pcmk_dbus_find_error(const DBusPendingCall *pending, DBusMessage *reply, DBusError *ret)
char * pcmk_dbus_get_property(DBusConnection *connection, const char *target, const char *obj, const gchar *iface, const char *name, property_callback_func callback, void *userdata, DBusPendingCall **pending, int timeout)
#define SYSTEMD_OVERRIDE_TEMPLATE
DBusMessage * pcmk_dbus_send_recv(DBusMessage *msg, DBusConnection *connection, DBusError *error, int timeout)
Execution failed, may be retried.
#define crm_info(fmt, args...)