Page MenuHomeClusterLabs Projects

No OneTemporary

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

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)

Event Timeline