Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4512564
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
47 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/services/dbus.c b/lib/services/dbus.c
index 66a98a041f..b424c0b81b 100644
--- a/lib/services/dbus.c
+++ b/lib/services/dbus.c
@@ -1,406 +1,393 @@
#include <crm_internal.h>
#include <crm/crm.h>
#include <crm/services.h>
#include <dbus/dbus.h>
#include <pcmk-dbus.h>
#define BUS_PROPERTY_IFACE "org.freedesktop.DBus.Properties"
static bool pcmk_dbus_error_check(DBusError *err, const char *prefix, const char *function, int line)
{
if (err && dbus_error_is_set(err)) {
do_crm_log_alias(LOG_ERR, __FILE__, function, line, "%s: DBus error '%s'", prefix, err->message);
dbus_error_free(err);
return TRUE;
}
return FALSE;
}
DBusConnection *pcmk_dbus_connect(void)
{
DBusError err;
DBusConnection *connection;
dbus_error_init(&err);
connection = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
pcmk_dbus_error_check(&err, "Could not connect to System DBus", __FUNCTION__, __LINE__);
return connection;
}
void pcmk_dbus_disconnect(DBusConnection *connection)
{
}
-bool pcmk_dbus_append_arg(DBusMessage *msg, int dtype, const void *value)
-{
- DBusMessageIter args;
-
- dbus_message_iter_init_append(msg, &args);
- if (!dbus_message_iter_append_basic(&args, dtype, value)) {
- crm_err("dbus_message_iter_append_basic(%c) failed", dtype);
- return FALSE;
- }
-
- return TRUE;
-}
-
bool
pcmk_dbus_find_error(const char *method, DBusPendingCall* pending, DBusMessage *reply, DBusError *ret)
{
DBusError error;
dbus_error_init(&error);
if(pending == NULL) {
error.name = "org.clusterlabs.pacemaker.NoRequest";
error.message = "No request sent";
} else if(reply == NULL) {
error.name = "org.clusterlabs.pacemaker.NoReply";
error.message = "No reply";
} else {
DBusMessageIter args;
int dtype = dbus_message_get_type(reply);
switch(dtype) {
case DBUS_MESSAGE_TYPE_METHOD_RETURN:
dbus_message_iter_init(reply, &args);
crm_trace("Call to %s returned '%s'", method, dbus_message_iter_get_signature(&args));
break;
case DBUS_MESSAGE_TYPE_INVALID:
error.message = "Invalid reply";
error.name = "org.clusterlabs.pacemaker.InvalidReply";
crm_err("Error processing %s response: %s", method, error.message);
break;
case DBUS_MESSAGE_TYPE_METHOD_CALL:
error.message = "Invalid reply (method call)";
error.name = "org.clusterlabs.pacemaker.InvalidReply.Method";
crm_err("Error processing %s response: %s", method, error.message);
break;
case DBUS_MESSAGE_TYPE_SIGNAL:
error.message = "Invalid reply (signal)";
error.name = "org.clusterlabs.pacemaker.InvalidReply.Signal";
crm_err("Error processing %s response: %s", method, error.message);
break;
case DBUS_MESSAGE_TYPE_ERROR:
dbus_set_error_from_message (&error, reply);
crm_info("%s error '%s': %s", method, error.name, error.message);
break;
default:
error.message = "Unknown reply type";
error.name = "org.clusterlabs.pacemaker.InvalidReply.Type";
crm_err("Error processing %s response: %s (%d)", method, error.message, dtype);
}
}
if(ret && (error.name || error.message)) {
*ret = error;
return TRUE;
}
return FALSE;
}
DBusMessage *pcmk_dbus_send_recv(DBusMessage *msg, DBusConnection *connection, DBusError *error)
{
const char *method = NULL;
DBusMessage *reply = NULL;
DBusPendingCall* pending = NULL;
CRM_ASSERT(dbus_message_get_type (msg) == DBUS_MESSAGE_TYPE_METHOD_CALL);
method = dbus_message_get_member (msg);
// send message and get a handle for a reply
if (!dbus_connection_send_with_reply (connection, msg, &pending, -1)) { // -1 is default timeout
if(error) {
error->message = "Call to dbus_connection_send_with_reply() failed";
error->name = "org.clusterlabs.pacemaker.SendFailed";
}
crm_err("Error sending %s request", method);
return NULL;
}
dbus_connection_flush(connection);
if(pending) {
/* block until we receive a reply */
dbus_pending_call_block(pending);
/* get the reply message */
reply = dbus_pending_call_steal_reply(pending);
}
if(pcmk_dbus_find_error(method, pending, reply, error)) {
crm_trace("Was error: '%s' '%s'", error->name, error->message);
if(reply) {
dbus_message_unref(reply);
reply = NULL;
}
}
if(pending) {
/* free the pending message handle */
dbus_pending_call_unref(pending);
}
return reply;
}
bool pcmk_dbus_send(DBusMessage *msg, DBusConnection *connection,
void(*done)(DBusPendingCall *pending, void *user_data), void *user_data)
{
DBusError error;
const char *method = NULL;
DBusPendingCall* pending = NULL;
dbus_error_init(&error);
CRM_ASSERT(dbus_message_get_type (msg) == DBUS_MESSAGE_TYPE_METHOD_CALL);
method = dbus_message_get_member (msg);
// send message and get a handle for a reply
if (!dbus_connection_send_with_reply (connection, msg, &pending, -1)) { // -1 is default timeout
crm_err("Send with reply failed for %s", method);
return FALSE;
} else if (pending == NULL) {
crm_err("No pending call found for %s", method);
return FALSE;
}
CRM_ASSERT(dbus_pending_call_set_notify(pending, done, user_data, NULL));
return TRUE;
}
bool pcmk_dbus_type_check(DBusMessage *msg, DBusMessageIter *field, int expected, const char *function, int line)
{
int dtype = 0;
DBusMessageIter lfield;
if(field == NULL) {
if(dbus_message_iter_init(msg, &lfield)) {
field = &lfield;
}
}
if(field == NULL) {
do_crm_log_alias(LOG_ERR, __FILE__, function, line,
"Empty parameter list in reply expecting '%c'", expected);
return FALSE;
}
dtype = dbus_message_iter_get_arg_type(field);
if(dtype != expected) {
DBusMessageIter args;
dbus_message_iter_init(msg, &args);
do_crm_log_alias(LOG_ERR, __FILE__, function, line,
"Unexepcted DBus type, expected %c instead of %c in '%s'",
expected, dtype, dbus_message_iter_get_signature(&args));
return FALSE;
}
return TRUE;
}
char *
pcmk_dbus_get_property(
DBusConnection *connection, const char *target, const char *obj, const gchar * iface, const char *name)
{
DBusMessage *msg;
DBusMessageIter args;
DBusMessageIter dict;
DBusMessage *reply = NULL;
/* DBusBasicValue value; */
const char *method = "GetAll";
char *output = NULL;
DBusError error;
/* desc = systemd_unit_property(path, BUS_NAME ".Unit", "Description"); */
dbus_error_init(&error);
crm_info("Calling: %s on %s", method, target);
msg = dbus_message_new_method_call(target, // target for the method call
obj, // object to call on
BUS_PROPERTY_IFACE, // interface to call on
method); // method name
if (NULL == msg) {
crm_err("Call to %s failed: No message", method);
return NULL;
}
- pcmk_dbus_append_arg(msg, DBUS_TYPE_STRING, &iface);
+ CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &iface, DBUS_TYPE_INVALID));
reply = pcmk_dbus_send_recv(msg, connection, &error);
dbus_message_unref(msg);
if(error.name) {
crm_err("Call to %s for %s failed: No reply", method, iface);
return NULL;
} else if (!dbus_message_iter_init(reply, &args)) {
crm_err("Cannot get properties for %s from %s", obj, iface);
return NULL;
}
if(!pcmk_dbus_type_check(reply, &args, DBUS_TYPE_ARRAY, __FUNCTION__, __LINE__)) {
crm_err("Call to %s failed: Message has invalid arguments", method);
dbus_message_unref(reply);
return NULL;
}
dbus_message_iter_recurse(&args, &dict);
while (dbus_message_iter_get_arg_type (&dict) != DBUS_TYPE_INVALID) {
DBusMessageIter sv;
DBusMessageIter v;
DBusBasicValue value;
if(!pcmk_dbus_type_check(reply, &dict, DBUS_TYPE_DICT_ENTRY, __FUNCTION__, __LINE__)) {
dbus_message_iter_next (&dict);
continue;
}
dbus_message_iter_recurse(&dict, &sv);
while (dbus_message_iter_get_arg_type (&sv) != DBUS_TYPE_INVALID) {
int dtype = dbus_message_iter_get_arg_type(&sv);
switch(dtype) {
case DBUS_TYPE_STRING:
dbus_message_iter_get_basic(&sv, &value);
crm_trace("Got: %s", value.str);
if(strcmp(value.str, name) != 0) {
dbus_message_iter_next (&sv); /* Skip the value */
}
break;
case DBUS_TYPE_VARIANT:
dbus_message_iter_recurse(&sv, &v);
if(pcmk_dbus_type_check(reply, &v, DBUS_TYPE_STRING, __FUNCTION__, __LINE__)) {
dbus_message_iter_get_basic(&v, &value);
crm_trace("Result: %s", value.str);
output = strdup(value.str);
}
break;
default:
pcmk_dbus_type_check(reply, &sv, DBUS_TYPE_STRING, __FUNCTION__, __LINE__);
}
dbus_message_iter_next (&sv);
}
dbus_message_iter_next (&dict);
}
crm_trace("Property %s[%s] is '%s'", obj, name, output);
return output;
}
static void pcmk_dbus_connection_dispatch(DBusConnection *connection, DBusDispatchStatus new_status, void *data){
crm_trace("status %d for %p", new_status, data);
if (new_status == DBUS_DISPATCH_DATA_REMAINS){
dbus_connection_dispatch(connection);
}
}
static int
pcmk_dbus_watch_dispatch(gpointer userdata)
{
DBusWatch *watch = userdata;
int flags = dbus_watch_get_flags(watch);
crm_trace("Dispatching %p with flags %d", watch, flags);
if(flags & DBUS_WATCH_READABLE) {
dbus_watch_handle(watch, DBUS_WATCH_READABLE);
} else {
dbus_watch_handle(watch, DBUS_WATCH_ERROR);
}
return 0;
}
static void
pcmk_dbus_watch_destroy(gpointer userdata)
{
crm_trace("Destroyed %p", userdata);
}
struct mainloop_fd_callbacks pcmk_dbus_cb = {
.dispatch = pcmk_dbus_watch_dispatch,
.destroy = pcmk_dbus_watch_destroy,
};
static dbus_bool_t
pcmk_dbus_watch_add(DBusWatch *watch, void *data){
int fd = dbus_watch_get_unix_fd(watch);
mainloop_io_t *client = mainloop_add_fd(
"dbus", G_PRIORITY_DEFAULT, fd, watch, &pcmk_dbus_cb);
crm_trace("Added %p with fd=%d", watch, fd);
dbus_watch_set_data(watch, client, NULL);
return TRUE;
}
static void
pcmk_dbus_watch_remove(DBusWatch *watch, void *data){
mainloop_io_t *client = dbus_watch_get_data(watch);
crm_trace("Removed %p", watch);
mainloop_del_fd(client);
}
static gboolean
pcmk_dbus_timeout_dispatch(gpointer data)
{
crm_trace("Timeout for %p");
dbus_timeout_handle(data);
return FALSE;
}
static dbus_bool_t
pcmk_dbus_timeout_add(DBusTimeout *timeout, void *data){
guint id = g_timeout_add(dbus_timeout_get_interval(timeout), pcmk_dbus_timeout_dispatch, timeout);
if(id) {
dbus_timeout_set_data(timeout, GUINT_TO_POINTER(id), NULL);
}
return TRUE;
}
static void
pcmk_dbus_timeout_remove(DBusTimeout *timeout, void *data){
void *vid = dbus_timeout_get_data(timeout);
guint id = GPOINTER_TO_UINT(vid);
if(id) {
g_source_remove(id);
dbus_timeout_set_data(timeout, 0, NULL);
}
}
static void
pcmk_dbus_timeout_toggle(DBusTimeout *timeout, void *data){
if(dbus_timeout_get_enabled(timeout)) {
pcmk_dbus_timeout_add(timeout, data);
} else {
pcmk_dbus_timeout_remove(timeout, data);
}
}
/* Inspired by http://www.kolej.mff.cuni.cz/~vesej3am/devel/dbus-select.c */
void pcmk_dbus_connection_setup_with_select(DBusConnection *c){
dbus_connection_set_timeout_functions(
c, pcmk_dbus_timeout_add, pcmk_dbus_timeout_remove, pcmk_dbus_timeout_toggle, NULL, NULL);
dbus_connection_set_watch_functions(c, pcmk_dbus_watch_add, pcmk_dbus_watch_remove, NULL, NULL, NULL);
dbus_connection_set_dispatch_status_function(c, pcmk_dbus_connection_dispatch, NULL, NULL);
pcmk_dbus_connection_dispatch(c, dbus_connection_get_dispatch_status(c), NULL);
}
diff --git a/lib/services/pcmk-dbus.h b/lib/services/pcmk-dbus.h
index c8d2234b7c..3b7a598a82 100644
--- a/lib/services/pcmk-dbus.h
+++ b/lib/services/pcmk-dbus.h
@@ -1,13 +1,12 @@
DBusConnection *pcmk_dbus_connect(void);
void pcmk_dbus_connection_setup_with_select(DBusConnection *c);
void pcmk_dbus_disconnect(DBusConnection *connection);
bool pcmk_dbus_send(DBusMessage *msg, DBusConnection *connection,
void(*done)(DBusPendingCall *pending, void *user_data), void *user_data);
DBusMessage *pcmk_dbus_send_recv(DBusMessage *msg, DBusConnection *connection, DBusError *error);
-bool pcmk_dbus_append_arg(DBusMessage *msg, int dtype, const void *value);
bool pcmk_dbus_type_check(DBusMessage *msg, DBusMessageIter *field, int expected, const char *function, int line);
char *pcmk_dbus_get_property(DBusConnection *connection, const char *target, const char *obj, const gchar * iface, const char *name);
bool pcmk_dbus_find_error(const char *method, DBusPendingCall* pending, DBusMessage *reply, DBusError *error);
diff --git a/lib/services/systemd.c b/lib/services/systemd.c
index b461c5f58f..374a03e226 100644
--- a/lib/services/systemd.c
+++ b/lib/services/systemd.c
@@ -1,530 +1,530 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Copyright (C) 2012 Andrew Beekhof <andrew@beekhof.net>
*/
#include <crm_internal.h>
#include <crm/crm.h>
#include <crm/services.h>
#include <crm/common/mainloop.h>
#include <gio/gio.h>
#include <services_private.h>
#include <systemd.h>
#include <dbus/dbus.h>
#include <pcmk-dbus.h>
#define BUS_NAME "org.freedesktop.systemd1"
#define BUS_PATH "/org/freedesktop/systemd1"
#define BUS_PROPERTY_IFACE "org.freedesktop.DBus.Properties"
/*
/usr/share/dbus-1/interfaces/org.freedesktop.systemd1.Manager.xml
*/
struct unit_info {
const char *id;
const char *description;
const char *load_state;
const char *active_state;
const char *sub_state;
const char *following;
const char *unit_path;
uint32_t job_id;
const char *job_type;
const char *job_path;
};
static DBusMessage *systemd_new_method(const char *iface, const char *method)
{
crm_trace("Calling: %s on %s", method, iface);
return dbus_message_new_method_call(BUS_NAME, // target for the method call
BUS_PATH, // object to call on
iface, // interface to call on
method); // method name
}
static DBusConnection* systemd_proxy = NULL;
static gboolean
systemd_init(void)
{
static int need_init = 1;
/* http://dbus.freedesktop.org/doc/api/html/group__DBusConnection.html */
if (need_init) {
need_init = 0;
systemd_proxy = pcmk_dbus_connect();
pcmk_dbus_connection_setup_with_select(systemd_proxy);
}
if (systemd_proxy == NULL) {
return FALSE;
}
return TRUE;
}
void
systemd_cleanup(void)
{
if (systemd_proxy) {
pcmk_dbus_disconnect(systemd_proxy);
systemd_proxy = NULL;
}
}
static char *
systemd_service_name(const char *name)
{
if (name == NULL) {
return NULL;
} else if (strstr(name, ".service")) {
return strdup(name);
}
return g_strdup_printf("%s.service", name);
}
static bool
systemd_daemon_reload(void)
{
const char *method = "Reload";
DBusMessage *reply = NULL;
DBusMessage *msg = systemd_new_method(BUS_NAME".Manager", method);
CRM_ASSERT(msg != NULL);
reply = pcmk_dbus_send_recv(msg, systemd_proxy, NULL);
dbus_message_unref(msg);
if(reply) {
dbus_message_unref(reply);
}
return TRUE;
}
static gboolean
systemd_unit_by_name(const gchar * arg_name, gchar ** out_unit)
{
DBusMessage *msg;
DBusMessage *reply = NULL;
const char *method = "GetUnit";
char *name = NULL;
DBusError error;
/*
<method name="GetUnit">
<arg name="name" type="s" direction="in"/>
<arg name="unit" type="o" direction="out"/>
</method>
<method name="LoadUnit">
<arg name="name" type="s" direction="in"/>
<arg name="unit" type="o" direction="out"/>
</method>
*/
if (systemd_init() == FALSE) {
return FALSE;
}
name = systemd_service_name(arg_name);
while(*out_unit == NULL) {
msg = systemd_new_method(BUS_NAME".Manager", method);
CRM_ASSERT(msg != NULL);
- pcmk_dbus_append_arg(msg, DBUS_TYPE_STRING, &name);
+ CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID));
dbus_error_init(&error);
reply = pcmk_dbus_send_recv(msg, systemd_proxy, &error);
dbus_message_unref(msg);
if(error.name) {
crm_info("Call to %s failed: %s", method, error.name);
} else if(pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH, __FUNCTION__, __LINE__)) {
if(out_unit) {
char *path = NULL;
dbus_message_get_args (reply, NULL,
DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID);
*out_unit = strdup(path);
}
dbus_message_unref(reply);
free(name);
return TRUE;
}
if(strcmp(method, "LoadUnit") != 0) {
method = "LoadUnit";
crm_debug("Cannot find %s, reloading the systemd manager configuration", name);
systemd_daemon_reload();
if(reply) {
dbus_message_unref(reply);
reply = NULL;
}
} else {
free(name);
return FALSE;
}
}
return FALSE;
}
GList *
systemd_unit_listall(void)
{
int lpc = 0;
GList *units = NULL;
DBusMessageIter args;
DBusMessageIter unit;
DBusMessageIter elem;
DBusMessage *msg = NULL;
DBusMessage *reply = NULL;
const char *method = "ListUnits";
DBusError error;
if (systemd_init() == FALSE) {
return NULL;
}
/*
" <method name=\"ListUnits\">\n" \
" <arg name=\"units\" type=\"a(ssssssouso)\" direction=\"out\"/>\n" \
" </method>\n" \
*/
dbus_error_init(&error);
msg = systemd_new_method(BUS_NAME".Manager", method);
CRM_ASSERT(msg != NULL);
reply = pcmk_dbus_send_recv(msg, systemd_proxy, &error);
dbus_message_unref(msg);
if(error.name) {
crm_err("Call to %s failed: %s", method, error.name);
return NULL;
} else if (!dbus_message_iter_init(reply, &args)) {
crm_err("Call to %s failed: Message has no arguments", method);
dbus_message_unref(reply);
return NULL;
}
if(!pcmk_dbus_type_check(reply, &args, DBUS_TYPE_ARRAY, __FUNCTION__, __LINE__)) {
crm_err("Call to %s failed: Message has invalid arguments", method);
dbus_message_unref(reply);
return NULL;
}
dbus_message_iter_recurse(&args, &unit);
while (dbus_message_iter_get_arg_type (&unit) != DBUS_TYPE_INVALID) {
DBusBasicValue value;
if(!pcmk_dbus_type_check(reply, &unit, DBUS_TYPE_STRUCT, __FUNCTION__, __LINE__)) {
continue;
}
dbus_message_iter_recurse(&unit, &elem);
if(!pcmk_dbus_type_check(reply, &elem, DBUS_TYPE_STRING, __FUNCTION__, __LINE__)) {
continue;
}
dbus_message_iter_get_basic(&elem, &value);
crm_trace("Got: %s", value.str);
if(value.str) {
char *match = strstr(value.str, ".service");
if (match) {
lpc++;
match[0] = 0;
units = g_list_append(units, strdup(value.str));
}
}
dbus_message_iter_next (&unit);
}
dbus_message_unref(reply);
crm_trace("Found %d systemd services", lpc);
return units;
}
gboolean
systemd_unit_exists(const char *name)
{
return systemd_unit_by_name(name, NULL);
}
static char *
systemd_unit_metadata(const char *name)
{
char *path = NULL;
char *meta = NULL;
char *desc = NULL;
CRM_ASSERT(systemd_init());
if (systemd_unit_by_name(name, &path)) {
desc = pcmk_dbus_get_property(systemd_proxy, BUS_NAME, path, BUS_NAME ".Unit", "Description");
} else {
desc = g_strdup_printf("systemd unit file for %s", name);
}
meta = g_strdup_printf("<?xml version=\"1.0\"?>\n"
"<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n"
"<resource-agent name=\"%s\" version=\"0.1\">\n"
" <version>1.0</version>\n"
" <longdesc lang=\"en\">\n"
" %s\n"
" </longdesc>\n"
" <shortdesc lang=\"en\">systemd unit file for %s</shortdesc>\n"
" <parameters>\n"
" </parameters>\n"
" <actions>\n"
" <action name=\"start\" timeout=\"15\" />\n"
" <action name=\"stop\" timeout=\"15\" />\n"
" <action name=\"status\" timeout=\"15\" />\n"
" <action name=\"restart\" timeout=\"15\" />\n"
" <action name=\"monitor\" timeout=\"15\" interval=\"15\" start-delay=\"15\" />\n"
" <action name=\"meta-data\" timeout=\"5\" />\n"
" </actions>\n"
" <special tag=\"systemd\">\n"
" </special>\n" "</resource-agent>\n", name, desc, name);
free(desc);
return meta;
}
static bool
systemd_mask_error(svc_action_t *op, const char *error)
{
crm_trace("Could not issue %s for %s: %s", op->action, op->rsc, error);
if(strstr(error, "org.freedesktop.systemd1.InvalidName")
|| strstr(error, "org.freedesktop.systemd1.LoadFailed")
|| strstr(error, "org.freedesktop.systemd1.NoSuchUnit")) {
if (safe_str_eq(op->action, "stop")) {
crm_trace("Masking %s failure for %s: unknown services are stopped", op->action, op->rsc);
op->rc = PCMK_OCF_OK;
} else {
crm_trace("Mapping %s failure for %s: unknown services are not installed", op->action, op->rsc);
op->rc = PCMK_OCF_NOT_INSTALLED;
op->status = PCMK_LRM_OP_NOT_INSTALLED;
}
return TRUE;
}
return FALSE;
}
static void
systemd_async_dispatch(DBusPendingCall *pending, void *user_data)
{
DBusError error;
DBusMessage *reply = NULL;
svc_action_t *op = user_data;
dbus_error_init(&error);
if(pending) {
reply = dbus_pending_call_steal_reply(pending);
}
if(pcmk_dbus_find_error(op->action, pending, reply, &error)) {
/* ignore "already started" or "not running" errors */
if (!systemd_mask_error(op, error.name)) {
crm_err("%s for %s: %s", op->action, op->rsc, error.message);
}
} else {
if(!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH, __FUNCTION__, __LINE__)) {
crm_warn("Call to %s passed but return type was unexpected", op->action);
op->rc = PCMK_OCF_OK;
} else {
const char *path = NULL;
dbus_message_get_args (reply, NULL,
DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID);
crm_info("Call to %s passed: %s", op->action, path);
op->rc = PCMK_OCF_OK;
}
}
operation_finalize(op);
if(pending) {
dbus_pending_call_unref(pending);
}
if(reply) {
dbus_message_unref(reply);
}
}
#define SYSTEMD_OVERRIDE_ROOT "/run/systemd/system/"
gboolean
systemd_unit_exec(svc_action_t * op, gboolean synchronous)
{
DBusError error;
char *unit = NULL;
const char *replace_s = "replace";
gboolean pass = FALSE;
const char *method = op->action;
char *name = systemd_service_name(op->agent);
DBusMessage *msg = NULL;
DBusMessage *reply = NULL;
dbus_error_init(&error);
op->rc = PCMK_OCF_UNKNOWN_ERROR;
CRM_ASSERT(systemd_init());
crm_debug("Performing %ssynchronous %s op on systemd unit %s named '%s'",
synchronous ? "" : "a", op->action, op->agent, op->rsc);
if (safe_str_eq(op->action, "meta-data")) {
op->stdout_data = systemd_unit_metadata(op->agent);
op->rc = PCMK_OCF_OK;
goto cleanup;
}
pass = systemd_unit_by_name(op->agent, &unit);
if (pass == FALSE) {
crm_debug("Could not obtain unit named '%s'", op->agent);
#if 0
if (error && strstr(error->message, "systemd1.NoSuchUnit")) {
op->rc = PCMK_OCF_NOT_INSTALLED;
op->status = PCMK_LRM_OP_NOT_INSTALLED;
}
#endif
goto cleanup;
}
if (safe_str_eq(op->action, "monitor") || safe_str_eq(method, "status")) {
char *state = pcmk_dbus_get_property(systemd_proxy, BUS_NAME, unit, BUS_NAME ".Unit", "ActiveState");
if (g_strcmp0(state, "active") == 0) {
op->rc = PCMK_OCF_OK;
} else {
op->rc = PCMK_OCF_NOT_RUNNING;
}
free(state);
goto cleanup;
} else if (g_strcmp0(method, "start") == 0) {
FILE *file_strm = NULL;
char *override_dir = g_strdup_printf("%s/%s", SYSTEMD_OVERRIDE_ROOT, unit);
char *override_file = g_strdup_printf("%s/50-pacemaker.conf", override_dir);
method = "StartUnit";
crm_build_path(override_dir, 0755);
file_strm = fopen(override_file, "w");
if (file_strm != NULL) {
int rc = fprintf(file_strm, "[Service]\nRestart=no");
if (rc < 0) {
crm_perror(LOG_ERR, "Cannot write to systemd override file %s: %s (%d)", override_file, pcmk_strerror(errno), errno);
}
} else {
crm_err("Cannot open systemd override file %s for writing: %s (%d)", override_file, pcmk_strerror(errno), errno);
}
if (file_strm != NULL) {
fflush(file_strm);
fclose(file_strm);
}
systemd_daemon_reload();
free(override_file);
free(override_dir);
} else if (g_strcmp0(method, "stop") == 0) {
char *override_file = g_strdup_printf("%s/%s/50-pacemaker.conf", SYSTEMD_OVERRIDE_ROOT, unit);
method = "StopUnit";
unlink(override_file);
free(override_file);
systemd_daemon_reload();
} else if (g_strcmp0(method, "restart") == 0) {
method = "RestartUnit";
} else {
op->rc = PCMK_OCF_UNIMPLEMENT_FEATURE;
goto cleanup;
}
crm_debug("Calling %s for %s: %s", method, op->rsc, unit);
msg = systemd_new_method(BUS_NAME".Manager", method);
CRM_ASSERT(msg != NULL);
/* (ss) */
- pcmk_dbus_append_arg(msg, DBUS_TYPE_STRING, &name);
- pcmk_dbus_append_arg(msg, DBUS_TYPE_STRING, &replace_s);
+ CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID));
+ CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &replace_s, DBUS_TYPE_INVALID));
if (synchronous == FALSE) {
free(unit);
free(name);
return pcmk_dbus_send(msg, systemd_proxy, systemd_async_dispatch, op);
}
dbus_error_init(&error);
reply = pcmk_dbus_send_recv(msg, systemd_proxy, &error);
if(error.name) {
/* ignore "already started" or "not running" errors */
if(!systemd_mask_error(op, error.name)) {
crm_err("Could not issue %s for %s: %s (%s)", method, op->rsc, error.name, unit);
}
goto cleanup;
} else if(!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH, __FUNCTION__, __LINE__)) {
crm_warn("Call to %s passed but return type was unexpected", op->action);
op->rc = PCMK_OCF_OK;
} else {
const char *path = NULL;
dbus_message_get_args (reply, NULL,
DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID);
crm_info("Call to %s passed: %s", op->action, path);
op->rc = PCMK_OCF_OK;
}
cleanup:
free(unit);
free(name);
if(msg) {
dbus_message_unref(msg);
}
if(reply) {
dbus_message_unref(reply);
}
if (synchronous == FALSE) {
operation_finalize(op);
return TRUE;
}
return op->rc == PCMK_OCF_OK;
}
diff --git a/lib/services/upstart.c b/lib/services/upstart.c
index 04f6059d07..a5a582428b 100644
--- a/lib/services/upstart.c
+++ b/lib/services/upstart.c
@@ -1,552 +1,552 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* File: upstart-dbus.c
* Copyright (C) 2010 Senko Rasic <senko.rasic@dobarkod.hr>
* Copyright (c) 2010 Ante Karamatic <ivoks@init.hr>
*
*
* Each exported function is standalone, and creates a new connection to
* the upstart daemon. This is because lrmd plugins fork off for exec,
* and if we try and share the connection, the whole thing blocks
* indefinitely.
*/
#include <crm_internal.h>
#include <stdio.h>
#include <crm/crm.h>
#include <crm/services.h>
#include <crm/common/mainloop.h>
#include <services_private.h>
#include <upstart.h>
#include <dbus/dbus.h>
#include <pcmk-dbus.h>
#include <glib.h>
#include <gio/gio.h>
#define BUS_NAME "com.ubuntu.Upstart"
#define BUS_PATH "/com/ubuntu/Upstart"
#define UPSTART_06_API BUS_NAME"0_6"
#define UPSTART_JOB_IFACE UPSTART_06_API".Job"
#define BUS_PROPERTY_IFACE "org.freedesktop.DBus.Properties"
/*
http://upstart.ubuntu.com/wiki/DBusInterface
*/
static DBusConnection *upstart_proxy = NULL;
static gboolean
upstart_init(void)
{
static int need_init = 1;
if (need_init) {
need_init = 0;
upstart_proxy = pcmk_dbus_connect();
pcmk_dbus_connection_setup_with_select(upstart_proxy);
}
if (upstart_proxy == NULL) {
return FALSE;
}
return TRUE;
}
void
upstart_cleanup(void)
{
if (upstart_proxy) {
pcmk_dbus_disconnect(upstart_proxy);
upstart_proxy = NULL;
}
}
static gboolean
upstart_job_by_name(const gchar * arg_name, gchar ** out_unit)
{
/*
com.ubuntu.Upstart0_6.GetJobByName (in String name, out ObjectPath job)
*/
DBusError error;
DBusMessage *msg;
DBusMessage *reply = NULL;
const char *method = "GetJobByName";
upstart_init();
msg = dbus_message_new_method_call(BUS_NAME, // target for the method call
BUS_PATH, // object to call on
UPSTART_06_API, // interface to call on
method); // method name
dbus_error_init(&error);
- pcmk_dbus_append_arg(msg, DBUS_TYPE_STRING, &arg_name);
+ CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &arg_name, DBUS_TYPE_INVALID));
reply = pcmk_dbus_send_recv(msg, upstart_proxy, &error);
dbus_message_unref(msg);
if(error.name) {
/* ignore "already started" or "not running" errors */
crm_err("Could not issue %s for %s: %s", method, arg_name, error.name);
} else if(!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH, __FUNCTION__, __LINE__)) {
crm_err("Invalid return type for %s", method);
} else {
if(out_unit) {
char *path = NULL;
dbus_message_get_args (reply, NULL,
DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID);
*out_unit = strdup(path);
}
dbus_message_unref(reply);
return TRUE;
}
if(reply) {
dbus_message_unref(reply);
}
return FALSE;
}
static void
fix(char *input, const char *search, char replace)
{
char *match = NULL;
int shuffle = strlen(search) - 1;
while (TRUE) {
int len, lpc;
match = strstr(input, search);
if (match == NULL) {
break;
}
crm_trace("Found: %s", match);
match[0] = replace;
len = strlen(match) - shuffle;
for (lpc = 1; lpc <= len; lpc++) {
match[lpc] = match[lpc + shuffle];
}
}
}
static char *
fix_upstart_name(const char *input)
{
char *output = strdup(input);
fix(output, "_2b", '+');
fix(output, "_2c", ',');
fix(output, "_2d", '-');
fix(output, "_2e", '.');
fix(output, "_40", '@');
fix(output, "_5f", '_');
return output;
}
GList *
upstart_job_listall(void)
{
GList *units = NULL;
DBusMessageIter args;
DBusMessageIter unit;
DBusMessage *msg = NULL;
DBusMessage *reply = NULL;
const char *method = "GetAllJobs";
DBusError error;
int lpc = 0;
if (upstart_init() == FALSE) {
return NULL;
}
/*
com.ubuntu.Upstart0_6.GetAllJobs (out <Array of ObjectPath> jobs)
*/
dbus_error_init(&error);
msg = dbus_message_new_method_call(BUS_NAME, // target for the method call
BUS_PATH, // object to call on
UPSTART_06_API, // interface to call on
method); // method name
CRM_ASSERT(msg != NULL);
reply = pcmk_dbus_send_recv(msg, upstart_proxy, &error);
dbus_message_unref(msg);
if(error.name) {
crm_err("Call to %s failed: %s", method, error.name);
return NULL;
} else if (!dbus_message_iter_init(reply, &args)) {
crm_err("Call to %s failed: Message has no arguments", method);
dbus_message_unref(reply);
return NULL;
}
if(!pcmk_dbus_type_check(reply, &args, DBUS_TYPE_ARRAY, __FUNCTION__, __LINE__)) {
crm_err("Call to %s failed: Message has invalid arguments", method);
dbus_message_unref(reply);
return NULL;
}
dbus_message_iter_recurse(&args, &unit);
while (dbus_message_iter_get_arg_type (&unit) != DBUS_TYPE_INVALID) {
DBusBasicValue value;
const char *job = NULL;
char *path = NULL;
if(!pcmk_dbus_type_check(reply, &unit, DBUS_TYPE_OBJECT_PATH, __FUNCTION__, __LINE__)) {
continue;
}
dbus_message_iter_get_basic(&unit, &value);
if(value.str) {
int llpc = 0;
path = value.str;
job = value.str;
while (path[llpc] != 0) {
if (path[llpc] == '/') {
job = path + llpc + 1;
}
llpc++;
}
lpc++;
crm_trace("%s -> %s\n", path, job);
units = g_list_append(units, fix_upstart_name(job));
}
dbus_message_iter_next (&unit);
}
dbus_message_unref(reply);
crm_trace("Found %d upstart jobs", lpc);
return units;
}
gboolean
upstart_job_exists(const char *name)
{
return upstart_job_by_name(name, NULL);
}
static char *
get_first_instance(const gchar * job)
{
char *instance = NULL;
const char *method = "GetAllInstances";
DBusError error;
DBusMessage *msg;
DBusMessage *reply;
DBusMessageIter args;
DBusMessageIter unit;
dbus_error_init(&error);
msg = dbus_message_new_method_call(BUS_NAME, // target for the method call
job, // object to call on
UPSTART_JOB_IFACE, // interface to call on
method); // method name
CRM_ASSERT(msg != NULL);
- pcmk_dbus_append_arg(msg, DBUS_TYPE_INVALID, NULL);
+ dbus_message_append_args(msg, DBUS_TYPE_INVALID);
reply = pcmk_dbus_send_recv(msg, upstart_proxy, &error);
dbus_message_unref(msg);
if(error.name) {
crm_err("Call to %s failed: %s", method, error.name);
goto done;
} else if (!dbus_message_iter_init(reply, &args)) {
crm_err("Call to %s failed: Message has no arguments", method);
goto done;
}
if(!pcmk_dbus_type_check(reply, &args, DBUS_TYPE_ARRAY, __FUNCTION__, __LINE__)) {
crm_err("Call to %s failed: Message has invalid arguments", method);
goto done;
}
dbus_message_iter_recurse(&args, &unit);
if(pcmk_dbus_type_check(reply, &unit, DBUS_TYPE_OBJECT_PATH, __FUNCTION__, __LINE__)) {
DBusBasicValue value;
dbus_message_iter_get_basic(&unit, &value);
if(value.str) {
instance = strdup(value.str);
crm_trace("Result: %s", instance);
}
}
done:
if(reply) {
dbus_message_unref(reply);
}
return instance;
}
gboolean
upstart_job_running(const gchar * name)
{
bool running = FALSE;
char *job = NULL;
if(upstart_job_by_name(name, &job)) {
char *path = get_first_instance(job);
if (path) {
char *state = pcmk_dbus_get_property(
upstart_proxy, BUS_NAME, path, UPSTART_06_API ".Instance", "state");
crm_info("State of %s: %s", name, state);
if (state) {
running = !g_strcmp0(state, "running");
}
free(state);
}
free(path);
}
free(job);
crm_info("%s is%s running", name, running ? "" : " not");
return running;
}
static char *
upstart_job_metadata(const char *name)
{
return g_strdup_printf("<?xml version=\"1.0\"?>\n"
"<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n"
"<resource-agent name=\"%s\" version=\"0.1\">\n"
" <version>1.0</version>\n"
" <longdesc lang=\"en\">\n"
" Upstart agent for controlling the system %s service\n"
" </longdesc>\n"
" <shortdesc lang=\"en\">%s upstart agent</shortdesc>\n"
" <parameters>\n"
" </parameters>\n"
" <actions>\n"
" <action name=\"start\" timeout=\"15\" />\n"
" <action name=\"stop\" timeout=\"15\" />\n"
" <action name=\"status\" timeout=\"15\" />\n"
" <action name=\"restart\" timeout=\"15\" />\n"
" <action name=\"monitor\" timeout=\"15\" interval=\"15\" start-delay=\"15\" />\n"
" <action name=\"meta-data\" timeout=\"5\" />\n"
" </actions>\n"
" <special tag=\"upstart\">\n"
" </special>\n" "</resource-agent>\n", name, name, name);
}
static bool
upstart_mask_error(svc_action_t *op, const char *error)
{
crm_trace("Could not issue %s for %s: %s", op->action, op->rsc, error);
if(strstr(error, UPSTART_06_API ".Error.UnknownInstance")) {
if(safe_str_eq(op->action, "stop")) {
crm_trace("Masking %s failure for %s: unknown services are stopped", op->action, op->rsc);
op->rc = PCMK_OCF_OK;
} else if(safe_str_eq(op->action, "start")) {
crm_trace("Mapping %s failure for %s: unknown services are not installed", op->action, op->rsc);
op->rc = PCMK_OCF_NOT_INSTALLED;
op->status = PCMK_LRM_OP_NOT_INSTALLED;
}
return TRUE;
} else if (safe_str_eq(op->action, "start")
&& strstr(error, UPSTART_06_API ".Error.AlreadyStarted")) {
crm_trace("Mapping %s failure for %s: starting a started resource is allowed", op->action, op->rsc);
op->rc = PCMK_OCF_OK;
return TRUE;
}
return FALSE;
}
static void
upstart_async_dispatch(DBusPendingCall *pending, void *user_data)
{
DBusError error;
DBusMessage *reply = NULL;
svc_action_t *op = user_data;
dbus_error_init(&error);
if(pending) {
reply = dbus_pending_call_steal_reply(pending);
}
if(pcmk_dbus_find_error(op->action, pending, reply, &error)) {
/* ignore "already started" or "not running" errors */
if (!upstart_mask_error(op, error.name)) {
crm_err("%s for %s: %s", op->action, op->rsc, error.message);
}
} else if (!g_strcmp0(op->action, "stop")) {
/* No return vaue */
op->rc = PCMK_OCF_OK;
} else {
if(!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH, __FUNCTION__, __LINE__)) {
crm_warn("Call to %s passed but return type was unexpected", op->action);
op->rc = PCMK_OCF_OK;
} else {
const char *path = NULL;
dbus_message_get_args (reply, NULL,
DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID);
crm_info("Call to %s passed: %s", op->action, path);
op->rc = PCMK_OCF_OK;
}
}
operation_finalize(op);
if(pending) {
dbus_pending_call_unref(pending);
}
if(reply) {
dbus_message_unref(reply);
}
}
gboolean
upstart_job_exec(svc_action_t * op, gboolean synchronous)
{
char *job = NULL;
int arg_wait = TRUE;
const char *arg_env = "pacemaker=1";
const char *action = op->action;
DBusError error;
DBusMessage *msg = NULL;
DBusMessage *reply = NULL;
DBusMessageIter iter, array_iter;
op->rc = PCMK_OCF_UNKNOWN_ERROR;
CRM_ASSERT(upstart_init());
if (safe_str_eq(op->action, "meta-data")) {
op->stdout_data = upstart_job_metadata(op->agent);
op->rc = PCMK_OCF_OK;
goto cleanup;
}
if(!upstart_job_by_name(op->agent, &job)) {
crm_debug("Could not obtain job named '%s' to %s", op->agent, action);
if (!g_strcmp0(action, "stop")) {
op->rc = PCMK_OCF_OK;
} else {
op->rc = PCMK_OCF_NOT_INSTALLED;
op->status = PCMK_LRM_OP_NOT_INSTALLED;
}
goto cleanup;
}
if (safe_str_eq(op->action, "monitor") || safe_str_eq(action, "status")) {
if (upstart_job_running(op->agent)) {
op->rc = PCMK_OCF_OK;
} else {
op->rc = PCMK_OCF_NOT_RUNNING;
}
goto cleanup;
} else if (!g_strcmp0(action, "start")) {
action = "Start";
} else if (!g_strcmp0(action, "stop")) {
action = "Stop";
} else if (!g_strcmp0(action, "restart")) {
action = "Restart";
} else {
op->rc = PCMK_OCF_UNIMPLEMENT_FEATURE;
goto cleanup;
}
crm_debug("Calling %s for %s on %s", action, op->rsc, job);
msg = dbus_message_new_method_call(BUS_NAME, // target for the method call
job, // object to call on
UPSTART_JOB_IFACE, // interface to call on
action); // method name
CRM_ASSERT(msg != NULL);
dbus_message_iter_init_append (msg, &iter);
CRM_LOG_ASSERT(dbus_message_iter_open_container (&iter,
DBUS_TYPE_ARRAY,
DBUS_TYPE_STRING_AS_STRING,
&array_iter));
CRM_LOG_ASSERT(dbus_message_iter_append_basic (&array_iter, DBUS_TYPE_STRING, &arg_env));
CRM_LOG_ASSERT(dbus_message_iter_close_container (&iter, &array_iter));
- pcmk_dbus_append_arg(msg, DBUS_TYPE_BOOLEAN, &arg_wait);
+ CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &arg_wait, DBUS_TYPE_INVALID));
if (synchronous == FALSE) {
free(job);
return pcmk_dbus_send(msg, upstart_proxy, upstart_async_dispatch, op);
}
dbus_error_init(&error);
reply = pcmk_dbus_send_recv(msg, upstart_proxy, &error);
if(error.name) {
if(!upstart_mask_error(op, error.name)) {
crm_err("Could not issue %s for %s: %s (%s)", action, op->rsc, error.name, job);
}
} else if (!g_strcmp0(op->action, "stop")) {
/* No return vaue */
op->rc = PCMK_OCF_OK;
} else if(!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH, __FUNCTION__, __LINE__)) {
crm_warn("Call to %s passed but return type was unexpected", op->action);
op->rc = PCMK_OCF_OK;
} else {
const char *path = NULL;
dbus_message_get_args (reply, NULL,
DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID);
crm_info("Call to %s passed: %s", op->action, path);
op->rc = PCMK_OCF_OK;
}
cleanup:
free(job);
if(msg) {
dbus_message_unref(msg);
}
if(reply) {
dbus_message_unref(reply);
}
if (synchronous == FALSE) {
operation_finalize(op);
return TRUE;
}
return op->rc == PCMK_OCF_OK;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Wed, Jun 25, 5:57 AM (19 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1952369
Default Alt Text
(47 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment