Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4512518
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
16 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/services/upstart.c b/lib/services/upstart.c
index 831e7cf050..195c3a473f 100644
--- a/lib/services/upstart.c
+++ b/lib/services/upstart.c
@@ -1,529 +1,539 @@
/*
* 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 <glib.h>
#include <gio/gio.h>
#define BUS_NAME "com.ubuntu.Upstart"
#define BUS_PATH "/com/ubuntu/Upstart"
#define BUS_MANAGER_IFACE BUS_NAME"0_6"
#define BUS_PROPERTY_IFACE "org.freedesktop.DBus.Properties"
/*
http://upstart.ubuntu.com/wiki/DBusInterface
*/
static GDBusProxy *upstart_proxy = NULL;
static GDBusProxy *
get_proxy(const char *path, const char *interface)
{
GError *error = NULL;
GDBusProxy *proxy = NULL;
#ifndef GLIB_DEPRECATED_IN_2_36
g_type_init();
#endif
if (path == NULL) {
path = BUS_PATH;
}
proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, /* GDBusInterfaceInfo */
BUS_NAME, path, interface,
NULL, /* GCancellable */ &error);
if (error) {
crm_err("Can't connect obtain proxy to %s interface: %s", interface, error->message);
g_error_free(error);
proxy = NULL;
}
return proxy;
}
static gboolean
upstart_init(void)
{
static int need_init = 1;
if (need_init) {
need_init = 0;
upstart_proxy = get_proxy(NULL, BUS_MANAGER_IFACE);
}
if (upstart_proxy == NULL) {
return FALSE;
}
return TRUE;
}
void
upstart_cleanup(void)
{
if (upstart_proxy) {
g_object_unref(upstart_proxy);
upstart_proxy = NULL;
}
}
static gboolean
upstart_job_by_name(GDBusProxy * proxy,
const gchar * arg_name,
gchar ** out_unit, GCancellable * cancellable, GError ** error)
{
/*
com.ubuntu.Upstart0_6.GetJobByName (in String name, out ObjectPath job)
*/
GVariant *_ret = g_dbus_proxy_call_sync(proxy, "GetJobByName", g_variant_new("(s)", arg_name),
G_DBUS_CALL_FLAGS_NONE, -1, cancellable, error);
if (_ret) {
g_variant_get(_ret, "(o)", out_unit);
g_variant_unref(_ret);
}
return _ret != NULL;
}
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_err("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;
GError *error = NULL;
GVariantIter *iter;
char *path = NULL;
GVariant *_ret = NULL;
int lpc = 0;
if (upstart_init() == FALSE) {
return NULL;
}
/*
com.ubuntu.Upstart0_6.GetAllJobs (out <Array of ObjectPath> jobs)
*/
_ret = g_dbus_proxy_call_sync(upstart_proxy, "GetAllJobs", g_variant_new("()"),
G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
if (error) {
crm_info("Call to GetAllJobs failed: %s", error->message);
g_error_free(error);
return NULL;
}
g_variant_get(_ret, "(ao)", &iter);
while (g_variant_iter_loop(iter, "o", &path)) {
int llpc = 0;
const char *job = path;
while (path[llpc] != 0) {
if (path[llpc] == '/') {
job = path + llpc + 1;
}
llpc++;
}
lpc++;
crm_trace("%s\n", path);
units = g_list_append(units, fix_upstart_name(job));
}
crm_info("Call to GetAllJobs passed: type '%s', count %d", g_variant_get_type_string(_ret),
lpc);
g_variant_iter_free(iter);
g_variant_unref(_ret);
return units;
}
gboolean
upstart_job_exists(const char *name)
{
char *path = NULL;
GError *error = NULL;
gboolean pass = FALSE;
if (upstart_init() == FALSE) {
return FALSE;
}
pass = upstart_job_by_name(upstart_proxy, name, &path, NULL, &error);
if (error) {
crm_trace("Call to ListUnits failed: %s", error->message);
g_error_free(error);
pass = FALSE;
} else if (pass) {
crm_trace("Got %s", path);
}
/* free(path) */
return pass;
}
static char *
upstart_job_property(const char *obj, const gchar * iface, const char *name)
{
+ char *output = NULL;
+
+#if !GLIB_CHECK_VERSION(2,28,0)
+ static bool err = TRUE;
+
+ if(err) {
+ crm_err("This version of glib is too old to support upstart jobs");
+ err = FALSE;
+ }
+#else
GError *error = NULL;
GDBusProxy *proxy;
GVariant *asv = NULL;
GVariant *value = NULL;
GVariant *_ret = NULL;
- char *output = NULL;
crm_info("Calling GetAll on %s", obj);
proxy = get_proxy(obj, BUS_PROPERTY_IFACE);
if (!proxy) {
return NULL;
}
_ret = g_dbus_proxy_call_sync(proxy, "GetAll", g_variant_new("(s)", iface),
G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
if (error) {
crm_err("Cannot get properties for %s: %s", g_dbus_proxy_get_object_path(proxy),
error->message);
g_error_free(error);
g_object_unref(proxy);
return NULL;
}
crm_info("Call to GetAll passed: type '%s' %d\n", g_variant_get_type_string(_ret),
g_variant_n_children(_ret));
asv = g_variant_get_child_value(_ret, 0);
crm_trace("asv type '%s' %d\n", g_variant_get_type_string(asv), g_variant_n_children(asv));
value = g_variant_lookup_value(asv, name, NULL);
if (value && g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
crm_info("Got value '%s' for %s[%s]", g_variant_get_string(value, NULL), obj, name);
output = g_variant_dup_string(value, NULL);
} else {
crm_info("No value for %s[%s]", obj, name);
}
g_object_unref(proxy);
g_variant_unref(_ret);
+#endif
return output;
}
static char *
get_first_instance(const gchar * job)
{
char *instance = NULL;
GError *error = NULL;
GDBusProxy *proxy = get_proxy(job, BUS_MANAGER_IFACE ".Job");
GVariant *_ret = g_dbus_proxy_call_sync(proxy, "GetAllInstances", g_variant_new("()"),
G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
if (error) {
crm_err("Cannot call GetAllInstances for %s: %s", job, error->message);
g_error_free(error);
return NULL;
}
crm_trace("Call to GetAllInstances passed: type '%s' %d\n", g_variant_get_type_string(_ret),
g_variant_n_children(_ret));
if (g_variant_n_children(_ret)) {
GVariant *tmp1 = g_variant_get_child_value(_ret, 0);
if (g_variant_n_children(tmp1)) {
GVariant *tmp2 = g_variant_get_child_value(tmp1, 0);
instance = g_variant_dup_string(tmp2, NULL);
}
}
crm_info("Result: %s", instance);
g_variant_unref(_ret);
return instance;
}
gboolean
upstart_job_running(const gchar * name)
{
char *job = NULL;
GError *error = NULL;
gboolean pass = FALSE;
pass = upstart_job_by_name(upstart_proxy, name, &job, NULL, &error);
if (error || pass == FALSE) {
crm_err("Call to ListUnits failed: %s", error ? error->message : "unknown");
if(error) {
g_error_free(error);
}
} else {
char *instance = get_first_instance(job);
pass = FALSE;
if (instance) {
if (instance) {
char *state =
upstart_job_property(instance, BUS_MANAGER_IFACE ".Instance", "state");
crm_info("State of %s: %s", name, state);
if (state) {
pass = !g_strcmp0(state, "running");
}
free(state);
}
}
free(instance);
}
crm_info("%s is%s running", name, pass ? "" : " not");
return pass;
}
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 void
upstart_job_exec_done(GObject * source_object, GAsyncResult * res, gpointer user_data)
{
GError *error = NULL;
GVariant *_ret = NULL;
svc_action_t *op = user_data;
GDBusProxy *proxy = G_DBUS_PROXY(source_object);
/* Obtain rc and stderr/out */
_ret = g_dbus_proxy_call_finish(proxy, res, &error);
if (error) {
/* ignore "already started" or "not running" errors */
if (safe_str_eq(op->action, "start")
&& strstr(error->message, BUS_MANAGER_IFACE ".Error.AlreadyStarted")) {
crm_trace("Masking Start failure for %s: already started", op->rsc);
op->rc = PCMK_OCF_OK;
} else if (safe_str_eq(op->action, "stop")
&& strstr(error->message, BUS_MANAGER_IFACE ".Error.UnknownInstance")) {
crm_trace("Masking Stop failure for %s: unknown services are stopped", op->rsc);
op->rc = PCMK_OCF_OK;
} else {
crm_err("Could not issue %s for %s: %s", op->action, op->rsc, error->message);
}
g_error_free(error);
} else if(g_variant_is_of_type (_ret, G_VARIANT_TYPE("(o)"))) {
char *path = NULL;
g_variant_get(_ret, "(o)", &path);
crm_info("Call to %s passed: type '%s' %s", op->action, g_variant_get_type_string(_ret),
path);
op->rc = PCMK_OCF_OK;
} else {
crm_err("Call to %s passed but return type was '%s' not '(o)'", op->action, g_variant_get_type_string(_ret));
op->rc = PCMK_OCF_OK;
}
operation_finalize(op);
g_object_unref(proxy);
if (_ret) {
g_variant_unref(_ret);
}
}
gboolean
upstart_job_exec(svc_action_t * op, gboolean synchronous)
{
char *job = NULL;
GError *error = NULL;
gboolean pass = FALSE;
gchar *no_args[] = { NULL };
const char *action = op->action;
GVariant *_ret = NULL;
GDBusProxy *job_proxy = NULL;
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;
}
pass = upstart_job_by_name(upstart_proxy, op->agent, &job, NULL, &error);
if (error) {
crm_debug("Could not obtain job named '%s': %s", op->agent, error->message);
pass = FALSE;
}
if (pass == FALSE) {
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;
}
job_proxy = get_proxy(job, BUS_MANAGER_IFACE ".Job");
crm_debug("Calling %s for %s: %s", action, op->rsc, job);
if (synchronous == FALSE) {
g_dbus_proxy_call(job_proxy, action, g_variant_new("(^asb)", no_args, TRUE),
G_DBUS_CALL_FLAGS_NONE, op->timeout, NULL, upstart_job_exec_done, op);
free(job);
return TRUE;
}
_ret = g_dbus_proxy_call_sync(job_proxy, action, g_variant_new("(^asb)", no_args, TRUE),
G_DBUS_CALL_FLAGS_NONE, op->timeout, NULL, &error);
if (error) {
/* ignore "already started" or "not running" errors */
if (safe_str_eq(action, "Start")
&& strstr(error->message, BUS_MANAGER_IFACE ".Error.AlreadyStarted")) {
crm_trace("Masking Start failure for %s: already started", op->rsc);
op->rc = PCMK_OCF_OK;
} else if (safe_str_eq(action, "Stop")
&& strstr(error->message, BUS_MANAGER_IFACE ".Error.UnknownInstance")) {
crm_trace("Masking Stop failure for %s: unknown services are stopped", op->rsc);
op->rc = PCMK_OCF_OK;
} else {
crm_err("Could not issue %s for %s: %s (%s)", action, op->rsc, error->message, job);
}
} else if(g_variant_is_of_type (_ret, G_VARIANT_TYPE("(o)"))) {
char *path = NULL;
g_variant_get(_ret, "(o)", &path);
crm_info("Call to %s passed: type '%s' %s", op->action, g_variant_get_type_string(_ret),
path);
op->rc = PCMK_OCF_OK;
} else {
crm_err("Call to %s passed but return type was '%s' not '(o)'", op->action, g_variant_get_type_string(_ret));
op->rc = PCMK_OCF_OK;
}
cleanup:
free(job);
if (error) {
g_error_free(error);
}
if (job_proxy) {
g_object_unref(job_proxy);
}
if (_ret) {
g_variant_unref(_ret);
}
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:36 AM (21 h, 34 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1952327
Default Alt Text
(16 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment