Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4512113
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
98 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/services/dbus.c b/lib/services/dbus.c
index 8c68908309..f44b59056f 100644
--- a/lib/services/dbus.c
+++ b/lib/services/dbus.c
@@ -1,535 +1,542 @@
#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"
struct db_getall_data
{
char *name;
char *target;
char *object;
void *userdata;
void (*callback)(const char *name, const char *value, void *userdata);
};
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);
if(pcmk_dbus_error_check(&err, "Could not connect to System DBus", __FUNCTION__, __LINE__)) {
return NULL;
}
if(connection) {
pcmk_dbus_connection_setup_with_select(connection);
}
return connection;
}
void pcmk_dbus_disconnect(DBusConnection *connection)
{
}
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/* aka. DBUS_TIMEOUT_USE_DEFAULT */)) {
if(error) {
dbus_error_init(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);
}
pcmk_dbus_find_error(method, pending, reply, error);
if(pending) {
/* free the pending message handle */
dbus_pending_call_unref(pending);
}
return reply;
}
DBusPendingCall* 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(done);
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/* aka. DBUS_TIMEOUT_USE_DEFAULT */)) { // -1 is default timeout
crm_err("Send with reply failed for %s", method);
return NULL;
} else if (pending == NULL) {
crm_err("No pending call found for %s", method);
return NULL;
}
crm_trace("DBus %s call sent", method);
if (dbus_pending_call_get_completed(pending)) {
crm_info("DBus %s call completed too soon", method);
if(done) {
#if 0
/* This sounds like a good idea, but allegedly it breaks things */
done(pending, user_data);
pending = NULL;
#else
CRM_ASSERT(dbus_pending_call_set_notify(pending, done, user_data, NULL));
#endif
}
} else if(done) {
CRM_ASSERT(dbus_pending_call_set_notify(pending, done, user_data, NULL));
}
return pending;
}
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 in '%s' instead of %c",
expected, dbus_message_iter_get_signature(&args), dtype);
return FALSE;
}
return TRUE;
}
static char *
pcmk_dbus_lookup_result(DBusMessage *reply, struct db_getall_data *data)
{
DBusError error;
char *output = NULL;
DBusMessageIter dict;
DBusMessageIter args;
if(pcmk_dbus_find_error("GetAll", (void*)&error, reply, &error)) {
crm_err("Cannot get properties from %s for %s", data->target, data->object);
goto cleanup;
}
dbus_message_iter_init(reply, &args);
if(!pcmk_dbus_type_check(reply, &args, DBUS_TYPE_ARRAY, __FUNCTION__, __LINE__)) {
crm_err("Invalid reply from %s for %s", data->target, data->object);
goto cleanup;
}
dbus_message_iter_recurse(&args, &dict);
while (dbus_message_iter_get_arg_type (&dict) != DBUS_TYPE_INVALID) {
DBusMessageIter sv;
DBusMessageIter v;
DBusBasicValue name;
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, &name);
if(data->name && strcmp(name.str, data->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("Property %s[%s] is '%s'", data->object, name.str, value.str);
if(data->callback) {
data->callback(name.str, value.str, data->userdata);
} else {
output = strdup(value.str);
}
if(data->name) {
goto cleanup;
}
}
break;
default:
pcmk_dbus_type_check(reply, &sv, DBUS_TYPE_STRING, __FUNCTION__, __LINE__);
}
dbus_message_iter_next (&sv);
}
dbus_message_iter_next (&dict);
}
if(data->name && data->callback) {
crm_trace("No value for property %s[%s]", data->object, data->name);
data->callback(data->name, NULL, data->userdata);
}
cleanup:
free(data->target);
free(data->object);
free(data->name);
free(data);
return output;
}
static void
pcmk_dbus_lookup_cb(DBusPendingCall *pending, void *user_data)
{
DBusMessage *reply = NULL;
if(pending) {
reply = dbus_pending_call_steal_reply(pending);
}
pcmk_dbus_lookup_result(reply, user_data);
+ if(pending) {
+ dbus_pending_call_unref(pending);
+ }
if(reply) {
dbus_message_unref(reply);
}
}
char *
pcmk_dbus_get_property(
DBusConnection *connection, const char *target, const char *obj, const gchar * iface, const char *name,
void (*callback)(const char *name, const char *value, void *userdata), void *userdata)
{
DBusMessage *msg;
const char *method = "GetAll";
char *output = NULL;
struct db_getall_data *query_data = NULL;
/* char *state = pcmk_dbus_get_property(systemd_proxy, BUS_NAME, unit, BUS_NAME ".Unit", "ActiveState"); */
crm_debug("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;
}
CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &iface, DBUS_TYPE_INVALID));
query_data = malloc(sizeof(struct db_getall_data));
if(query_data == NULL) {
crm_err("Call to %s failed: malloc failed", method);
return NULL;
}
query_data->target = strdup(target);
query_data->object = strdup(obj);
query_data->callback = callback;
query_data->userdata = userdata;
query_data->name = NULL;
if(name) {
query_data->name = strdup(name);
}
if(query_data->callback) {
pcmk_dbus_send(msg, connection, pcmk_dbus_lookup_cb, query_data);
} else {
DBusMessage *reply = pcmk_dbus_send_recv(msg, connection, NULL);
output = pcmk_dbus_lookup_result(reply, query_data);
if(reply) {
dbus_message_unref(reply);
}
}
dbus_message_unref(msg);
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);
+
+ while (dbus_connection_get_dispatch_status(connection) == DBUS_DISPATCH_DATA_REMAINS) {
+ dbus_connection_dispatch(connection);
+ }
}
}
/* Copied from dbus-watch.c */
static const char*
dbus_watch_flags_to_string (int flags)
{
const char *watch_type;
if ((flags & DBUS_WATCH_READABLE) &&
(flags & DBUS_WATCH_WRITABLE))
watch_type = "readwrite";
else if (flags & DBUS_WATCH_READABLE)
watch_type = "read";
else if (flags & DBUS_WATCH_WRITABLE)
watch_type = "write";
else
watch_type = "not read or write";
return watch_type;
}
static int
pcmk_dbus_watch_dispatch(gpointer userdata)
{
bool oom = FALSE;
DBusWatch *watch = userdata;
int flags = dbus_watch_get_flags(watch);
bool enabled = dbus_watch_get_enabled (watch);
mainloop_io_t *client = dbus_watch_get_data(watch);
crm_trace("Dispatching client %p: %s", client, dbus_watch_flags_to_string(flags));
if (enabled && is_set(flags, DBUS_WATCH_READABLE)) {
oom = !dbus_watch_handle(watch, flags);
} else if (enabled && is_set(flags, DBUS_WATCH_READABLE)) {
oom = !dbus_watch_handle(watch, flags);
} else if(enabled) {
oom = !dbus_watch_handle(watch, DBUS_WATCH_ERROR);
}
if(flags != dbus_watch_get_flags(watch)) {
flags = dbus_watch_get_flags(watch);
crm_trace("Dispatched client %p: %s (%d)", client, dbus_watch_flags_to_string(flags), flags);
}
if(oom) {
crm_err("DBus encountered OOM while attempting to dispatch %p (%s)", client, dbus_watch_flags_to_string(flags));
}
return 0;
}
static void
pcmk_dbus_watch_destroy(gpointer userdata)
{
mainloop_io_t *client = dbus_watch_get_data(userdata);
crm_trace("Destroyed %p", client);
}
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 watch %p with fd=%d to client %p", watch, fd, client);
dbus_watch_set_data(watch, client, NULL);
return TRUE;
}
static void
pcmk_dbus_watch_toggle(DBusWatch *watch, void *data)
{
mainloop_io_t *client = dbus_watch_get_data(watch);
crm_notice("DBus client %p is now %s", client, dbus_watch_get_enabled(watch)?"enabled":"disabled");
}
static void
pcmk_dbus_watch_remove(DBusWatch *watch, void *data){
mainloop_io_t *client = dbus_watch_get_data(watch);
crm_trace("Removed client %p (%p)", client, data);
mainloop_del_fd(client);
}
static gboolean
pcmk_dbus_timeout_dispatch(gpointer data)
{
crm_info("Timeout %p expired", data);
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);
crm_trace("Adding timeout %p (%ld)", timeout, dbus_timeout_get_interval(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);
crm_trace("Removing timeout %p (%p)", timeout, data);
if(id) {
g_source_remove(id);
dbus_timeout_set_data(timeout, 0, NULL);
}
}
static void
pcmk_dbus_timeout_toggle(DBusTimeout *timeout, void *data){
bool enabled = dbus_timeout_get_enabled(timeout);
crm_trace("Toggling timeout for %p to %s", timeout, enabled?"off":"on");
if(enabled) {
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, pcmk_dbus_watch_toggle, 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/systemd.c b/lib/services/systemd.c
index df815561aa..51ade44aaa 100644
--- a/lib/services/systemd.c
+++ b/lib/services/systemd.c
@@ -1,667 +1,665 @@
/*
* 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
*/
gboolean
systemd_unit_exec_with_unit(svc_action_t * op, const char *unit);
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;
};
struct pcmk_dbus_data
{
char *name;
char *unit;
DBusError error;
svc_action_t *op;
void (*callback)(DBusMessage *reply, svc_action_t *op);
};
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();
}
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 void
systemd_daemon_reload_complete(DBusPendingCall *pending, void *user_data)
{
DBusError error;
DBusMessage *reply = NULL;
unsigned int reload_count = GPOINTER_TO_UINT(user_data);
dbus_error_init(&error);
if(pending) {
reply = dbus_pending_call_steal_reply(pending);
}
if(pcmk_dbus_find_error("Reload", pending, reply, &error)) {
crm_err("Could not issue systemd reload %d: %s", reload_count, error.message);
} else {
crm_trace("Reload %d complete", reload_count);
}
if(pending) {
dbus_pending_call_unref(pending);
}
if(reply) {
dbus_message_unref(reply);
}
}
static bool
systemd_daemon_reload(void)
{
static unsigned int reload_count = 0;
const char *method = "Reload";
reload_count++;
if(reload_count % 10 == 0) {
DBusMessage *msg = systemd_new_method(BUS_NAME".Manager", method);
CRM_ASSERT(msg != NULL);
pcmk_dbus_send(msg, systemd_proxy, systemd_daemon_reload_complete, GUINT_TO_POINTER(reload_count));
dbus_message_unref(msg);
}
return TRUE;
}
static const char *
systemd_loadunit_result(DBusMessage *reply, svc_action_t * op)
{
const char *path = NULL;
if(pcmk_dbus_find_error("LoadUnit", (void*)&path, reply, NULL)) {
if(op) {
crm_warn("No unit found for %s", op->rsc);
}
} else if(pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH, __FUNCTION__, __LINE__)) {
dbus_message_get_args (reply, NULL,
DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID);
}
if(op) {
systemd_unit_exec_with_unit(op, path);
}
return path;
}
static void
systemd_loadunit_cb(DBusPendingCall *pending, void *user_data)
{
DBusMessage *reply = NULL;
svc_action_t * op = user_data;
if(pending) {
reply = dbus_pending_call_steal_reply(pending);
}
if(op) {
crm_trace("Got result: %p for %p for %s, %s", reply, pending, op->rsc, op->action);
} else {
crm_trace("Got result: %p for %p", reply, pending);
}
systemd_loadunit_result(reply, user_data);
+ if(pending) {
+ dbus_pending_call_unref(pending);
+ }
if(reply) {
dbus_message_unref(reply);
}
}
static char *
systemd_unit_by_name(const gchar * arg_name, svc_action_t *op)
{
DBusMessage *msg;
DBusMessage *reply = NULL;
char *name = NULL;
/*
Equivalent to GetUnit if its already loaded
<method name="LoadUnit">
<arg name="name" type="s" direction="in"/>
<arg name="unit" type="o" direction="out"/>
</method>
*/
if (systemd_init() == FALSE) {
return FALSE;
}
msg = systemd_new_method(BUS_NAME".Manager", "LoadUnit");
CRM_ASSERT(msg != NULL);
name = systemd_service_name(arg_name);
CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID));
free(name);
if(op == NULL || op->synchronous) {
const char *unit = NULL;
char *munit = NULL;
DBusError error;
dbus_error_init(&error);
reply = pcmk_dbus_send_recv(msg, systemd_proxy, &error);
dbus_message_unref(msg);
unit = systemd_loadunit_result(reply, op);
if(unit) {
munit = strdup(unit);
}
if(reply) {
dbus_message_unref(reply);
}
return munit;
}
pcmk_dbus_send(msg, systemd_proxy, systemd_loadunit_cb, op);
+ dbus_message_unref(msg);
return NULL;
}
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 (reply == NULL) {
crm_err("Call to %s failed: Message has no reply", method);
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)
{
char *unit = NULL;
/* Note: Makes a blocking dbus calls
* Used by resources_find_service_class() when resource class=service
*/
unit = systemd_unit_by_name(name, NULL);
if(unit) {
free(unit);
return TRUE;
}
return FALSE;
}
static char *
systemd_unit_metadata(const char *name)
{
char *meta = NULL;
char *desc = NULL;
char *path = systemd_unit_by_name(name, NULL);
if (path) {
/* TODO: Worth a making blocking call for? Probably not. Possibly if cached. */
desc = pcmk_dbus_get_property(systemd_proxy, BUS_NAME, path, BUS_NAME ".Unit", "Description", NULL, NULL);
} 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);
free(path);
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_exec_result(DBusMessage *reply, svc_action_t *op)
{
DBusError error;
if(pcmk_dbus_find_error(op->action, (void*)&error, reply, &error)) {
/* ignore "already started" or "not running" errors */
if (!systemd_mask_error(op, error.name)) {
crm_err("Could not issue %s for %s: %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);
}
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(op) {
crm_trace("Got result: %p for %p for %s, %s", reply, pending, op->rsc, op->action);
} else {
crm_trace("Got result: %p for %p", reply, pending);
}
op->opaque->pending = NULL;
systemd_exec_result(reply, op);
if(pending) {
dbus_pending_call_unref(pending);
}
if(reply) {
dbus_message_unref(reply);
}
}
#define SYSTEMD_OVERRIDE_ROOT "/run/systemd/system/"
static void
systemd_unit_check(const char *name, const char *state, void *userdata)
{
svc_action_t * op = userdata;
crm_trace("Resource %s has %s='%s'", op->rsc, name, state);
if(state == NULL) {
op->rc = PCMK_OCF_NOT_RUNNING;
} else if (g_strcmp0(state, "active") == 0) {
op->rc = PCMK_OCF_OK;
} else if (g_strcmp0(state, "activating") == 0) {
op->rc = PCMK_OCF_PENDING;
} else {
op->rc = PCMK_OCF_NOT_RUNNING;
}
if (op->synchronous == FALSE) {
op->opaque->pending = NULL;
operation_finalize(op);
}
}
gboolean
systemd_unit_exec_with_unit(svc_action_t * op, const char *unit)
{
const char *method = op->action;
DBusMessage *msg = NULL;
DBusMessage *reply = NULL;
CRM_ASSERT(unit);
if (unit == NULL) {
crm_debug("Could not obtain unit named '%s'", op->agent);
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(method, "status")) {
char *state = pcmk_dbus_get_property(systemd_proxy, BUS_NAME, unit, BUS_NAME ".Unit", "ActiveState",
op->synchronous?NULL:systemd_unit_check, op);
if (op->synchronous) {
systemd_unit_check("ActiveState", state, op);
free(state);
return op->rc == PCMK_OCF_OK;
}
return TRUE;
} 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/%s/50-pacemaker.conf", SYSTEMD_OVERRIDE_ROOT, unit);
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", override_file);
}
} else {
crm_err("Cannot open systemd override file %s for writing", override_file);
}
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) */
{
const char *replace_s = "replace";
char *name = systemd_service_name(op->agent);
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));
free(name);
}
if (op->synchronous == FALSE) {
DBusPendingCall* pending = pcmk_dbus_send(msg, systemd_proxy, systemd_async_dispatch, op);
+ dbus_message_unref(msg);
if(pending) {
dbus_pending_call_ref(pending);
op->opaque->pending = pending;
return TRUE;
}
return FALSE;
} else {
DBusError error;
reply = pcmk_dbus_send_recv(msg, systemd_proxy, &error);
+ dbus_message_unref(msg);
systemd_exec_result(reply, op);
if(reply) {
dbus_message_unref(reply);
}
- if(msg) {
- dbus_message_unref(msg);
- }
-
return FALSE;
}
- if(msg) {
- dbus_message_unref(msg);
- }
-
cleanup:
if (op->synchronous == FALSE) {
operation_finalize(op);
return TRUE;
}
return op->rc == PCMK_OCF_OK;
}
static gboolean
systemd_timeout_callback(gpointer p)
{
svc_action_t * op = p;
op->opaque->timerid = 0;
crm_warn("%s operation on systemd unit %s named '%s' timed out", op->action, op->agent, op->rsc);
operation_finalize(op);
return FALSE;
}
gboolean
systemd_unit_exec(svc_action_t * op)
{
char *unit = NULL;
CRM_ASSERT(op);
CRM_ASSERT(systemd_init());
op->rc = PCMK_OCF_UNKNOWN_ERROR;
crm_debug("Performing %ssynchronous %s op on systemd unit %s named '%s'",
op->synchronous ? "" : "a", op->action, op->agent, op->rsc);
if (safe_str_eq(op->action, "meta-data")) {
/* TODO: See if we can teach the lrmd not to make these calls synchronously */
op->stdout_data = systemd_unit_metadata(op->agent);
op->rc = PCMK_OCF_OK;
if (op->synchronous == FALSE) {
operation_finalize(op);
}
return TRUE;
}
unit = systemd_unit_by_name(op->agent, op);
free(unit);
if (op->synchronous == FALSE) {
op->opaque->timerid = g_timeout_add(op->timeout + 5000, systemd_timeout_callback, op);
return TRUE;
}
return op->rc == PCMK_OCF_OK;
}
diff --git a/lrmd/regression.py.in b/lrmd/regression.py.in
index 9c37a63410..d8c00a0b25 100755
--- a/lrmd/regression.py.in
+++ b/lrmd/regression.py.in
@@ -1,1044 +1,1072 @@
#!/usr/bin/python
#
# 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
# of the License, or (at your option) any later version.
#
# This program 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 program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
import os
import sys
import subprocess
import shlex
import time
# Where to find test binaries
# Prefer the source tree if available
build_dir="@abs_top_builddir@"
test_dir=sys.path[0]
new_path=os.environ['PATH']
if os.path.exists("%s/regression.py.in" % test_dir):
print "Running tests from the source tree: %s (%s)" % (build_dir, test_dir)
new_path = "%s/lrmd:%s" % (build_dir, new_path) # For lrmd, lrmd_test and pacemaker_remoted
new_path = "%s/tools:%s" % (build_dir, new_path) # For crm_resource
new_path = "%s/fencing:%s" % (build_dir, new_path) # For stonithd
else:
print "Running tests from the install tree: @CRM_DAEMON_DIR@ (not %s)" % test_dir
new_path = "@CRM_DAEMON_DIR@:%s" % (new_path) # For stonithd, lrmd, lrmd_test and pacemaker_remoted
print new_path
os.environ['PATH']=new_path
def output_from_command(command, no_wait=0):
test = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE)
if no_wait == 0:
test.wait()
else:
return 0
return test.communicate()[0].split("\n")
class Test:
def __init__(self, name, description, verbose = 0, tls = 0):
self.name = name
self.description = description
self.cmds = []
if tls:
self.daemon_location = "pacemaker_remoted"
else:
self.daemon_location = "lrmd"
self.test_tool_location = "lrmd_test"
self.verbose = verbose
self.tls = tls
self.result_txt = ""
self.cmd_tool_output = ""
self.result_exitcode = 0;
self.lrmd_process = None
self.stonith_process = None
self.executed = 0
def __new_cmd(self, cmd, args, exitcode, stdout_match = "", no_wait = 0, stdout_negative_match = "", kill=None):
if self.verbose and cmd == self.test_tool_location:
args = args + " -V "
if (cmd == self.test_tool_location) and self.tls:
args = args + " -S "
self.cmds.append(
{
"cmd" : cmd,
"kill" : kill,
"args" : args,
"expected_exitcode" : exitcode,
"stdout_match" : stdout_match,
"stdout_negative_match" : stdout_negative_match,
"no_wait" : no_wait,
"cmd_output" : "",
}
)
def start_environment(self):
### make sure we are in full control here ###
cmd = shlex.split("killall -q -9 stonithd lt-stonithd lrmd lt-lrmd lrmd_test lt-lrmd_test pacemaker_remoted")
test = subprocess.Popen(cmd, stdout=subprocess.PIPE)
test.wait()
additional_args = ""
if self.tls == 0:
self.stonith_process = subprocess.Popen(shlex.split("stonithd -s"))
if self.verbose:
additional_args = additional_args + " -V"
self.lrmd_process = subprocess.Popen(shlex.split("%s %s -l /tmp/lrmd-regression.log" % (self.daemon_location, additional_args)))
time.sleep(1)
def clean_environment(self):
if self.lrmd_process:
self.lrmd_process.terminate()
self.lrmd_process.wait()
if self.verbose:
print "Daemon output"
f = open('/tmp/lrmd-regression.log', 'r')
for line in f.readlines():
print line.strip()
os.remove('/tmp/lrmd-regression.log')
if self.stonith_process:
self.stonith_process.terminate()
self.stonith_process.wait()
self.lrmd_process = None
self.stonith_process = None
def add_sys_cmd(self, cmd, args):
self.__new_cmd(cmd, args, 0, "")
def add_sys_cmd_no_wait(self, cmd, args):
self.__new_cmd(cmd, args, 0, "", 1)
def add_cmd_check_stdout(self, args, match, no_match = ""):
self.__new_cmd(self.test_tool_location, args, 0, match, 0, no_match)
def add_cmd(self, args):
self.__new_cmd(self.test_tool_location, args, 0, "")
def add_cmd_and_kill(self, killProc, args):
self.__new_cmd(self.test_tool_location, args, 0, "", kill=killProc)
def add_expected_fail_cmd(self, args):
self.__new_cmd(self.test_tool_location, args, 1, "")
def get_exitcode(self):
return self.result_exitcode
def print_result(self, filler):
print "%s%s" % (filler, self.result_txt)
def run_cmd(self, args):
cmd = shlex.split(args['args'])
cmd.insert(0, args['cmd'])
if self.verbose:
print "\n\nRunning: "+" ".join(cmd)
test = subprocess.Popen(cmd, stdout=subprocess.PIPE)
if args['kill']:
if self.verbose:
print "Also running: "+args['kill']
### Typically the kill argument is used to detect some sort of
### failure. Without yeilding for a few seconds here the process
### launched earlier that is listening for the failure may not have time
### to connect to the lrmd.
time.sleep(2)
subprocess.Popen(shlex.split(args['kill']))
if args['no_wait'] == 0:
test.wait()
else:
return 0
output = test.communicate()[0]
if args['stdout_match'] != "" and output.count(args['stdout_match']) == 0:
test.returncode = -2
print "STDOUT string '%s' was not found in cmd output" % (args['stdout_match'])
if args['stdout_negative_match'] != "" and output.count(args['stdout_negative_match']) != 0:
test.returncode = -2
print "STDOUT string '%s' was found in cmd output" % (args['stdout_negative_match'])
args['cmd_output'] = output
return test.returncode;
def run(self):
res = 0
i = 1
if self.tls and self.name.count("stonith") != 0:
self.result_txt = "SKIPPED - '%s' - disabled when testing pacemaker_remote" % (self.name)
print self.result_txt
return res
self.start_environment()
if self.verbose:
print "\n--- START TEST - %s" % self.name
self.result_txt = "SUCCESS - '%s'" % (self.name)
self.result_exitcode = 0
for cmd in self.cmds:
res = self.run_cmd(cmd)
if res != cmd['expected_exitcode']:
print cmd['cmd_output']
print "Step %d FAILED - command returned %d, expected %d" % (i, res, cmd['expected_exitcode'])
self.result_txt = "FAILURE - '%s' failed at step %d. Command: lrmd_test %s" % (self.name, i, cmd['args'])
self.result_exitcode = -1
break
else:
if self.verbose:
print cmd['cmd_output'].strip()
print "Step %d SUCCESS" % (i)
i = i + 1
self.clean_environment()
print self.result_txt
if self.verbose:
print "--- END TEST - %s\n" % self.name
self.executed = 1
return res
class Tests:
def __init__(self, verbose = 0, tls = 0):
self.tests = []
self.verbose = verbose
self.tls = tls;
self.rsc_classes = output_from_command("crm_resource --list-standards")
self.rsc_classes = self.rsc_classes[:-1] # Strip trailing empty line
self.need_authkey = 0
self.action_timeout = " -t 5000 "
if self.tls:
self.rsc_classes.remove("stonith")
if "systemd" in self.rsc_classes:
# the lrmd_dummy_daemon requires this, we are importing it
# here just to guarantee it is installed before allowing this
# script to run. Otherwise, running without this import being
# available will make all the systemd tests look like they fail,
# which is really scary looking. I'd rather see the import fail.
import systemd.daemon
print "Testing "+repr(self.rsc_classes)
self.common_cmds = {
"ocf_reg_line" : "-c register_rsc -r ocf_test_rsc "+self.action_timeout+" -C ocf -P pacemaker -T Dummy",
"ocf_reg_event" : "-l \"NEW_EVENT event_type:register rsc_id:ocf_test_rsc action:none rc:ok op_status:complete\"",
"ocf_unreg_line" : "-c unregister_rsc -r \"ocf_test_rsc\" "+self.action_timeout,
"ocf_unreg_event" : "-l \"NEW_EVENT event_type:unregister rsc_id:ocf_test_rsc action:none rc:ok op_status:complete\"",
"ocf_start_line" : "-c exec -r \"ocf_test_rsc\" -a \"start\" "+self.action_timeout,
"ocf_start_event" : "-l \"NEW_EVENT event_type:exec_complete rsc_id:ocf_test_rsc action:start rc:ok op_status:complete\" ",
"ocf_stop_line" : "-c exec -r \"ocf_test_rsc\" -a \"stop\" "+self.action_timeout,
"ocf_stop_event" : "-l \"NEW_EVENT event_type:exec_complete rsc_id:ocf_test_rsc action:stop rc:ok op_status:complete\" ",
"ocf_monitor_line" : "-c exec -r \"ocf_test_rsc\" -a \"monitor\" -i \"2000\" "+self.action_timeout,
"ocf_monitor_event" : "-l \"NEW_EVENT event_type:exec_complete rsc_id:ocf_test_rsc action:monitor rc:ok op_status:complete\" "+self.action_timeout,
"ocf_cancel_line" : "-c cancel -r \"ocf_test_rsc\" -a \"monitor\" -i \"2000\" -t \"3000\" ",
"ocf_cancel_event" : "-l \"NEW_EVENT event_type:exec_complete rsc_id:ocf_test_rsc action:monitor rc:ok op_status:Cancelled\" ",
"systemd_reg_line" : "-c register_rsc -r systemd_test_rsc "+self.action_timeout+" -C systemd -T lrmd_dummy_daemon",
"systemd_reg_event" : "-l \"NEW_EVENT event_type:register rsc_id:systemd_test_rsc action:none rc:ok op_status:complete\"",
"systemd_unreg_line" : "-c unregister_rsc -r \"systemd_test_rsc\" "+self.action_timeout,
"systemd_unreg_event" : "-l \"NEW_EVENT event_type:unregister rsc_id:systemd_test_rsc action:none rc:ok op_status:complete\"",
"systemd_start_line" : "-c exec -r \"systemd_test_rsc\" -a \"start\" "+self.action_timeout,
"systemd_start_event" : "-l \"NEW_EVENT event_type:exec_complete rsc_id:systemd_test_rsc action:start rc:ok op_status:complete\" ",
"systemd_stop_line" : "-c exec -r \"systemd_test_rsc\" -a \"stop\" "+self.action_timeout,
"systemd_stop_event" : "-l \"NEW_EVENT event_type:exec_complete rsc_id:systemd_test_rsc action:stop rc:ok op_status:complete\" ",
"systemd_monitor_line" : "-c exec -r \"systemd_test_rsc\" -a \"monitor\" -i \"2000\" "+self.action_timeout,
"systemd_monitor_event" : "-l \"NEW_EVENT event_type:exec_complete rsc_id:systemd_test_rsc action:monitor rc:ok op_status:complete\" "+self.action_timeout,
"systemd_cancel_line" : "-c cancel -r \"systemd_test_rsc\" -a \"monitor\" -i \"2000\" -t \"3000\" ",
"systemd_cancel_event" : "-l \"NEW_EVENT event_type:exec_complete rsc_id:systemd_test_rsc action:monitor rc:ok op_status:Cancelled\" ",
"upstart_reg_line" : "-c register_rsc -r upstart_test_rsc "+self.action_timeout+" -C upstart -T lrmd_dummy_daemon",
"upstart_reg_event" : "-l \"NEW_EVENT event_type:register rsc_id:upstart_test_rsc action:none rc:ok op_status:complete\"",
"upstart_unreg_line" : "-c unregister_rsc -r \"upstart_test_rsc\" "+self.action_timeout,
"upstart_unreg_event" : "-l \"NEW_EVENT event_type:unregister rsc_id:upstart_test_rsc action:none rc:ok op_status:complete\"",
"upstart_start_line" : "-c exec -r \"upstart_test_rsc\" -a \"start\" "+self.action_timeout,
"upstart_start_event" : "-l \"NEW_EVENT event_type:exec_complete rsc_id:upstart_test_rsc action:start rc:ok op_status:complete\" ",
"upstart_stop_line" : "-c exec -r \"upstart_test_rsc\" -a \"stop\" "+self.action_timeout,
"upstart_stop_event" : "-l \"NEW_EVENT event_type:exec_complete rsc_id:upstart_test_rsc action:stop rc:ok op_status:complete\" ",
"upstart_monitor_line" : "-c exec -r \"upstart_test_rsc\" -a \"monitor\" -i \"2000\" "+self.action_timeout,
"upstart_monitor_event" : "-l \"NEW_EVENT event_type:exec_complete rsc_id:upstart_test_rsc action:monitor rc:ok op_status:complete\" "+self.action_timeout,
"upstart_cancel_line" : "-c cancel -r \"upstart_test_rsc\" -a \"monitor\" -i \"2000\" -t \"3000\" ",
"upstart_cancel_event" : "-l \"NEW_EVENT event_type:exec_complete rsc_id:upstart_test_rsc action:monitor rc:ok op_status:Cancelled\" ",
"service_reg_line" : "-c register_rsc -r service_test_rsc "+self.action_timeout+" -C service -T LSBDummy",
"service_reg_event" : "-l \"NEW_EVENT event_type:register rsc_id:service_test_rsc action:none rc:ok op_status:complete\"",
"service_unreg_line" : "-c unregister_rsc -r \"service_test_rsc\" "+self.action_timeout,
"service_unreg_event" : "-l \"NEW_EVENT event_type:unregister rsc_id:service_test_rsc action:none rc:ok op_status:complete\"",
"service_start_line" : "-c exec -r \"service_test_rsc\" -a \"start\" "+self.action_timeout,
"service_start_event" : "-l \"NEW_EVENT event_type:exec_complete rsc_id:service_test_rsc action:start rc:ok op_status:complete\" ",
"service_stop_line" : "-c exec -r \"service_test_rsc\" -a \"stop\" "+self.action_timeout,
"service_stop_event" : "-l \"NEW_EVENT event_type:exec_complete rsc_id:service_test_rsc action:stop rc:ok op_status:complete\" ",
"service_monitor_line" : "-c exec -r \"service_test_rsc\" -a \"monitor\" -i \"2000\" "+self.action_timeout,
"service_monitor_event" : "-l \"NEW_EVENT event_type:exec_complete rsc_id:service_test_rsc action:monitor rc:ok op_status:complete\" "+self.action_timeout,
"service_cancel_line" : "-c cancel -r \"service_test_rsc\" -a \"monitor\" -i \"2000\" -t \"3000\" ",
"service_cancel_event" : "-l \"NEW_EVENT event_type:exec_complete rsc_id:service_test_rsc action:monitor rc:ok op_status:Cancelled\" ",
"lsb_reg_line" : "-c register_rsc -r lsb_test_rsc "+self.action_timeout+" -C lsb -T LSBDummy",
"lsb_reg_event" : "-l \"NEW_EVENT event_type:register rsc_id:lsb_test_rsc action:none rc:ok op_status:complete\" ",
"lsb_unreg_line" : "-c unregister_rsc -r \"lsb_test_rsc\" "+self.action_timeout,
"lsb_unreg_event" : "-l \"NEW_EVENT event_type:unregister rsc_id:lsb_test_rsc action:none rc:ok op_status:complete\"",
"lsb_start_line" : "-c exec -r \"lsb_test_rsc\" -a \"start\" "+self.action_timeout,
"lsb_start_event" : "-l \"NEW_EVENT event_type:exec_complete rsc_id:lsb_test_rsc action:start rc:ok op_status:complete\" ",
"lsb_stop_line" : "-c exec -r \"lsb_test_rsc\" -a \"stop\" "+self.action_timeout,
"lsb_stop_event" : "-l \"NEW_EVENT event_type:exec_complete rsc_id:lsb_test_rsc action:stop rc:ok op_status:complete\" ",
"lsb_monitor_line" : "-c exec -r \"lsb_test_rsc\" -a status -i \"2000\" "+self.action_timeout,
"lsb_monitor_event" : "-l \"NEW_EVENT event_type:exec_complete rsc_id:lsb_test_rsc action:status rc:ok op_status:complete\" "+self.action_timeout,
"lsb_cancel_line" : "-c cancel -r \"lsb_test_rsc\" -a \"status\" -i \"2000\" -t \"3000\" ",
"lsb_cancel_event" : "-l \"NEW_EVENT event_type:exec_complete rsc_id:lsb_test_rsc action:status rc:ok op_status:Cancelled\" ",
"stonith_reg_line" : "-c register_rsc -r stonith_test_rsc "+self.action_timeout+" -C stonith -P pacemaker -T fence_dummy_monitor",
"stonith_reg_event" : "-l \"NEW_EVENT event_type:register rsc_id:stonith_test_rsc action:none rc:ok op_status:complete\" ",
"stonith_unreg_line" : "-c unregister_rsc -r \"stonith_test_rsc\" "+self.action_timeout,
"stonith_unreg_event" : "-l \"NEW_EVENT event_type:unregister rsc_id:stonith_test_rsc action:none rc:ok op_status:complete\"",
"stonith_start_line" : "-c exec -r \"stonith_test_rsc\" -a \"start\" -t 8000 ",
"stonith_start_event" : "-l \"NEW_EVENT event_type:exec_complete rsc_id:stonith_test_rsc action:start rc:ok op_status:complete\" ",
"stonith_stop_line" : "-c exec -r \"stonith_test_rsc\" -a \"stop\" "+self.action_timeout,
"stonith_stop_event" : "-l \"NEW_EVENT event_type:exec_complete rsc_id:stonith_test_rsc action:stop rc:ok op_status:complete\" ",
"stonith_monitor_line" : "-c exec -r \"stonith_test_rsc\" -a \"monitor\" -i \"2000\" "+self.action_timeout,
"stonith_monitor_event" : "-l \"NEW_EVENT event_type:exec_complete rsc_id:stonith_test_rsc action:monitor rc:ok op_status:complete\" "+self.action_timeout,
"stonith_cancel_line" : "-c cancel -r \"stonith_test_rsc\" -a \"monitor\" -i \"2000\" -t \"3000\" ",
"stonith_cancel_event" : "-l \"NEW_EVENT event_type:exec_complete rsc_id:stonith_test_rsc action:monitor rc:ok op_status:Cancelled\" ",
}
def new_test(self, name, description):
test = Test(name, description, self.verbose, self.tls)
self.tests.append(test)
return test
def setup_test_environment(self):
os.system("service pacemaker_remote stop")
self.cleanup_test_environment()
if self.tls and not os.path.isfile("/etc/pacemaker/authkey"):
self.need_authkey = 1
os.system("mkdir -p /etc/pacemaker")
os.system("dd if=/dev/urandom of=/etc/pacemaker/authkey bs=4096 count=1")
### Make fake systemd daemon and unit file ###
dummy_daemon = """#!/bin/python
import time, systemd.daemon
time.sleep(3)
systemd.daemon.notify("READY=1")
while True: time.sleep(5)
"""
dummy_service_file = """
[Unit]
Description=Dummy resource that takes a while to start
[Service]
Type=notify
ExecStart=/usr/sbin/lrmd_dummy_daemon
"""
dummy_upstart_job = ("""
description "Dummy service for regression tests"
exec dd if=/dev/random of=/dev/null
""")
dummy_fence_sleep_agent = ("""#!/usr/bin/python
import sys
import time
def main():
for line in sys.stdin.readlines():
if line.count("monitor") > 0:
time.sleep(30000)
sys.exit(0)
sys.exit(-1)
if __name__ == "__main__":
main()
""")
dummy_fence_agent = ("""#!/usr/bin/python
import sys
def main():
for line in sys.stdin.readlines():
if line.count("monitor") > 0:
sys.exit(0)
if line.count("metadata") > 0:
print '<resource-agent name="fence_dummy_monitor" shortdesc="Dummy Fence agent for testing">'
print ' <longdesc>dummy description.</longdesc>'
print ' <vendor-url>http://www.example.com</vendor-url>'
print ' <parameters>'
print ' <parameter name="action" unique="0" required="1">'
print ' <getopt mixed="-o, --action=[action]"/>'
print ' <content type="string" default="reboot"/>'
print ' <shortdesc lang="en">Fencing Action</shortdesc>'
print ' </parameter>'
print ' <parameter name="port" unique="0" required="0">'
print ' <getopt mixed="-n, --plug=[id]"/>'
print ' <content type="string"/>'
print ' <shortdesc lang="en">Physical plug number or name of virtual machine</shortdesc>'
print ' </parameter>'
print ' </parameters>'
print ' <actions>'
print ' <action name="on"/>'
print ' <action name="off"/>'
print ' <action name="monitor"/>'
print ' <action name="metadata"/>'
print ' </actions>'
print '</resource-agent>'
sys.exit(0)
sys.exit(-1)
if __name__ == "__main__":
main()
""")
os.system("cat <<-END >>/etc/init/lrmd_dummy_daemon.conf\n%s\nEND" % (dummy_upstart_job))
os.system("cat <<-END >>/usr/sbin/lrmd_dummy_daemon\n%s\nEND" % (dummy_daemon))
os.system("cat <<-END >>/lib/systemd/system/lrmd_dummy_daemon.service\n%s\nEND" % (dummy_service_file))
os.system("chmod a+x /usr/sbin/lrmd_dummy_daemon")
os.system("cat <<-END >>/usr/sbin/fence_dummy_sleep\n%s\nEND" % (dummy_fence_sleep_agent))
os.system("chmod 711 /usr/sbin/fence_dummy_sleep")
os.system("cat <<-END >>/usr/sbin/fence_dummy_monitor\n%s\nEND" % (dummy_fence_agent))
os.system("chmod 711 /usr/sbin/fence_dummy_monitor")
if os.path.exists("%s/cts/LSBDummy" % build_dir):
print "Using %s/cts/LSBDummy" % build_dir
os.system("cp %s/cts/LSBDummy /etc/init.d/LSBDummy" % build_dir)
if not os.path.exists("@OCF_RA_DIR@/pacemaker"):
os.system("mkdir -p @OCF_RA_DIR@/pacemaker/")
# Install helper OCF agents
for ra in [ "Dummy", "Stateful", "ping" ]:
os.system("cp %s/extra/resources/%s @OCF_RA_DIR@/pacemaker/%s" % (build_dir, ra, ra))
os.system("chmod a+x @OCF_RA_DIR@/pacemaker/%s" % (ra))
else:
# Assume it's installed
print "Using @datadir@/@PACKAGE@/tests/cts/LSBDummy"
os.system("cp @datadir@/@PACKAGE@/tests/cts/LSBDummy /etc/init.d/LSBDummy")
os.system("chmod a+x /etc/init.d/LSBDummy")
os.system("ls -al /etc/init.d/LSBDummy")
os.system("mkdir -p @CRM_CORE_DIR@/root")
if os.path.exists("/bin/systemctl"):
os.system("systemctl daemon-reload")
def cleanup_test_environment(self):
if self.need_authkey:
os.system("rm -f /etc/pacemaker/authkey")
os.system("rm -f /etc/init.d/LSBDummy")
os.system("rm -f /lib/systemd/system/lrmd_dummy_daemon.service")
os.system("rm -f /usr/sbin/lrmd_dummy_daemon")
os.system("rm -f /usr/sbin/fence_dummy_monitor")
os.system("rm -f /usr/sbin/fence_dummy_sleep")
if os.path.exists("/bin/systemctl"):
os.system("systemctl daemon-reload")
### These are tests that should apply to all resource classes ###
def build_generic_tests(self):
common_cmds = self.common_cmds
### register/unregister tests ###
for rsc in self.rsc_classes:
test = self.new_test("generic_registration_%s" % (rsc), "Simple resource registration test for %s standard" % (rsc))
test.add_cmd(common_cmds["%s_reg_line" % (rsc)] + " " + common_cmds["%s_reg_event" % (rsc)])
test.add_cmd(common_cmds["%s_unreg_line" % (rsc)] + " " + common_cmds["%s_unreg_event" % (rsc)])
### start/stop tests ###
for rsc in self.rsc_classes:
test = self.new_test("generic_start_stop_%s" % (rsc), "Simple start and stop test for %s standard" % (rsc))
test.add_cmd(common_cmds["%s_reg_line" % (rsc)] + " " + common_cmds["%s_reg_event" % (rsc)])
test.add_cmd(common_cmds["%s_start_line" % (rsc)] + " " + common_cmds["%s_start_event" % (rsc)])
test.add_cmd(common_cmds["%s_stop_line" % (rsc)] + " " + common_cmds["%s_stop_event" % (rsc)])
test.add_cmd(common_cmds["%s_unreg_line" % (rsc)] + " " + common_cmds["%s_unreg_event" % (rsc)])
### monitor cancel test ###
for rsc in self.rsc_classes:
test = self.new_test("generic_monitor_cancel_%s" % (rsc), "Simple monitor cancel test for %s standard" % (rsc))
test.add_cmd(common_cmds["%s_reg_line" % (rsc)] + " " + common_cmds["%s_reg_event" % (rsc)])
test.add_cmd(common_cmds["%s_start_line" % (rsc)] + " " + common_cmds["%s_start_event" % (rsc)])
test.add_cmd(common_cmds["%s_monitor_line" % (rsc)] + " " + common_cmds["%s_monitor_event" % (rsc)])
test.add_cmd(common_cmds["%s_monitor_event" % (rsc)]) ### If this fails, that means the monitor may not be getting rescheduled ####
test.add_cmd(common_cmds["%s_monitor_event" % (rsc)]) ### If this fails, that means the monitor may not be getting rescheduled ####
test.add_cmd(common_cmds["%s_cancel_line" % (rsc)] + " " + common_cmds["%s_cancel_event" % (rsc)])
test.add_expected_fail_cmd(common_cmds["%s_monitor_event" % (rsc)]) ### If this happens the monitor did not actually cancel correctly. ###
test.add_expected_fail_cmd(common_cmds["%s_monitor_event" % (rsc)]) ### If this happens the monitor did not actually cancel correctly. ###
test.add_cmd(common_cmds["%s_stop_line" % (rsc)] + " " + common_cmds["%s_stop_event" % (rsc)])
test.add_cmd(common_cmds["%s_unreg_line" % (rsc)] + " " + common_cmds["%s_unreg_event" % (rsc)])
### monitor duplicate test ###
for rsc in self.rsc_classes:
test = self.new_test("generic_monitor_duplicate_%s" % (rsc), "Test creation and canceling of duplicate monitors for %s standard" % (rsc))
test.add_cmd(common_cmds["%s_reg_line" % (rsc)] + " " + common_cmds["%s_reg_event" % (rsc)])
test.add_cmd(common_cmds["%s_start_line" % (rsc)] + " " + common_cmds["%s_start_event" % (rsc)])
test.add_cmd(common_cmds["%s_monitor_line" % (rsc)] + " " + common_cmds["%s_monitor_event" % (rsc)])
test.add_cmd(common_cmds["%s_monitor_event" % (rsc)]) ### If this fails, that means the monitor may not be getting rescheduled ####
test.add_cmd(common_cmds["%s_monitor_event" % (rsc)]) ### If this fails, that means the monitor may not be getting rescheduled ####
# Add the duplicate monitors.
test.add_cmd(common_cmds["%s_monitor_line" % (rsc)] + " " + common_cmds["%s_monitor_event" % (rsc)])
test.add_cmd(common_cmds["%s_monitor_line" % (rsc)] + " " + common_cmds["%s_monitor_event" % (rsc)])
test.add_cmd(common_cmds["%s_monitor_line" % (rsc)] + " " + common_cmds["%s_monitor_event" % (rsc)])
test.add_cmd(common_cmds["%s_monitor_line" % (rsc)] + " " + common_cmds["%s_monitor_event" % (rsc)])
# verify we still get update events
test.add_cmd(common_cmds["%s_monitor_event" % (rsc)]) ### If this fails, that means the monitor may not be getting rescheduled ####
# cancel the monitor, if the duplicate merged with the original, we should no longer see monitor updates
test.add_cmd(common_cmds["%s_cancel_line" % (rsc)] + " " + common_cmds["%s_cancel_event" % (rsc)])
test.add_expected_fail_cmd(common_cmds["%s_monitor_event" % (rsc)]) ### If this happens the monitor did not actually cancel correctly. ###
test.add_expected_fail_cmd(common_cmds["%s_monitor_event" % (rsc)]) ### If this happens the monitor did not actually cancel correctly. ###
test.add_cmd(common_cmds["%s_stop_line" % (rsc)] + " " + common_cmds["%s_stop_event" % (rsc)])
test.add_cmd(common_cmds["%s_unreg_line" % (rsc)] + " " + common_cmds["%s_unreg_event" % (rsc)])
### stop implies cancel test ###
for rsc in self.rsc_classes:
test = self.new_test("generic_stop_implies_cancel_%s" % (rsc), "Verify stopping a resource implies cancel of recurring ops for %s standard" % (rsc))
test.add_cmd(common_cmds["%s_reg_line" % (rsc)] + " " + common_cmds["%s_reg_event" % (rsc)])
test.add_cmd(common_cmds["%s_start_line" % (rsc)] + " " + common_cmds["%s_start_event" % (rsc)])
test.add_cmd(common_cmds["%s_monitor_line" % (rsc)] + " " + common_cmds["%s_monitor_event" % (rsc)])
test.add_cmd(common_cmds["%s_monitor_event" % (rsc)]) ### If this fails, that means the monitor may not be getting rescheduled ####
test.add_cmd(common_cmds["%s_monitor_event" % (rsc)]) ### If this fails, that means the monitor may not be getting rescheduled ####
test.add_cmd(common_cmds["%s_stop_line" % (rsc)] + " " + common_cmds["%s_stop_event" % (rsc)])
test.add_expected_fail_cmd(common_cmds["%s_monitor_event" % (rsc)]) ### If this happens the monitor did not actually cancel correctly. ###
test.add_expected_fail_cmd(common_cmds["%s_monitor_event" % (rsc)]) ### If this happens the monitor did not actually cancel correctly. ###
test.add_cmd(common_cmds["%s_unreg_line" % (rsc)] + " " + common_cmds["%s_unreg_event" % (rsc)])
### These are complex tests that involve managing multiple resouces of different types ###
def build_multi_rsc_tests(self):
common_cmds = self.common_cmds
# do not use service and systemd at the same time, it is the same resource.
### register start monitor stop unregister resources of each type at the same time. ###
test = self.new_test("multi_rsc_start_stop_all", "Start, monitor, and stop resources of multiple types and classes")
for rsc in self.rsc_classes:
test.add_cmd(common_cmds["%s_reg_line" % (rsc)] + " " + common_cmds["%s_reg_event" % (rsc)])
for rsc in self.rsc_classes:
test.add_cmd(common_cmds["%s_start_line" % (rsc)] + " " + common_cmds["%s_start_event" % (rsc)])
for rsc in self.rsc_classes:
test.add_cmd(common_cmds["%s_monitor_line" % (rsc)] + " " + common_cmds["%s_monitor_event" % (rsc)])
for rsc in self.rsc_classes:
test.add_cmd(common_cmds["%s_monitor_event" % (rsc)]) ### If this fails, that means the monitor is not being rescheduled ####
for rsc in self.rsc_classes:
test.add_cmd(common_cmds["%s_cancel_line" % (rsc)] + " " + common_cmds["%s_cancel_event" % (rsc)])
for rsc in self.rsc_classes:
test.add_cmd(common_cmds["%s_stop_line" % (rsc)] + " " + common_cmds["%s_stop_event" % (rsc)])
for rsc in self.rsc_classes:
test.add_cmd(common_cmds["%s_unreg_line" % (rsc)] + " " + common_cmds["%s_unreg_event" % (rsc)])
### These are tests related to how the lrmd handles failures. ###
def build_negative_tests(self):
### ocf start timeout test ###
test = self.new_test("ocf_start_timeout", "Force start timeout to occur, verify start failure.")
test.add_cmd("-c register_rsc -r \"test_rsc\" -C \"ocf\" -P \"pacemaker\" -T \"Dummy\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:register rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
test.add_cmd("-c exec -r \"test_rsc\" -a \"start\" -k \"op_sleep\" -v \"5\" -t 1000 -w") # -t must be less than self.action_timeout
test.add_cmd("-l "
"\"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:start rc:unknown error op_status:Timed Out\" "+self.action_timeout)
test.add_cmd("-c exec -r test_rsc -a stop "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:stop rc:ok op_status:complete\" ")
test.add_cmd("-c unregister_rsc -r test_rsc "+self.action_timeout+
"-l \"NEW_EVENT event_type:unregister rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
### stonith start timeout test ###
test = self.new_test("stonith_start_timeout", "Force start timeout to occur, verify start failure.")
test.add_cmd("-c register_rsc -r \"test_rsc\" -C \"stonith\" -P \"pacemaker\" -T \"fence_dummy_sleep\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:register rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
test.add_cmd("-c exec -r \"test_rsc\" -a \"start\" -t 1000 -w") # -t must be less than self.action_timeout
test.add_cmd("-l "
"\"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:start rc:unknown error op_status:Timed Out\" "+self.action_timeout)
test.add_cmd("-c exec -r test_rsc -a stop "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:stop rc:ok op_status:complete\" ")
test.add_cmd("-c unregister_rsc -r test_rsc "+self.action_timeout+
"-l \"NEW_EVENT event_type:unregister rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
### stonith component fail ###
common_cmds = self.common_cmds
test = self.new_test("stonith_component_fail", "Kill stonith component after lrmd connects")
test.add_cmd(common_cmds["stonith_reg_line"] + " " + common_cmds["stonith_reg_event"])
test.add_cmd(common_cmds["stonith_start_line"] + " " + common_cmds["stonith_start_event"])
test.add_cmd("-c exec -r \"stonith_test_rsc\" -a \"monitor\" -i \"600000\" "
"-l \"NEW_EVENT event_type:exec_complete rsc_id:stonith_test_rsc action:monitor rc:ok op_status:complete\" "+self.action_timeout)
test.add_cmd_and_kill("killall -9 -q stonithd lt-stonithd" ,"-l \"NEW_EVENT event_type:exec_complete rsc_id:stonith_test_rsc action:monitor rc:unknown error op_status:error\" -t 15000")
test.add_cmd(common_cmds["stonith_unreg_line"] + " " + common_cmds["stonith_unreg_event"])
### monitor fail for ocf resources ###
test = self.new_test("monitor_fail_ocf", "Force ocf monitor to fail, verify failure is reported.")
test.add_cmd("-c register_rsc -r \"test_rsc\" -C \"ocf\" -P \"pacemaker\" -T \"Dummy\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:register rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
test.add_cmd("-c exec -r \"test_rsc\" -a \"start\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:start rc:ok op_status:complete\" ")
test.add_cmd("-c exec -r \"test_rsc\" -a \"start\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:start rc:ok op_status:complete\" ")
test.add_cmd("-c exec -r \"test_rsc\" -a \"monitor\" -i \"100\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:ok op_status:complete\" ")
test.add_cmd("-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:ok op_status:complete\" "+self.action_timeout)
test.add_cmd("-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:ok op_status:complete\" "+self.action_timeout)
test.add_cmd_and_kill("rm -f @localstatedir@/run/Dummy-test_rsc.state", "-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:not running op_status:complete\" -t 6000")
test.add_cmd("-c cancel -r \"test_rsc\" -a \"monitor\" -i \"100\" -t \"3000\" "
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:not running op_status:Cancelled\" ")
test.add_expected_fail_cmd("-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:not running op_status:complete\" "+self.action_timeout)
test.add_expected_fail_cmd("-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:ok op_status:complete\" "+self.action_timeout)
test.add_cmd("-c unregister_rsc -r \"test_rsc\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:unregister rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
### verify notify changes only for monitor operation. ###
test = self.new_test("monitor_changes_only", "Verify when flag is set, only monitor changes are notified.")
test.add_cmd("-c register_rsc -r \"test_rsc\" -C \"ocf\" -P \"pacemaker\" -T \"Dummy\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:register rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
test.add_cmd("-c exec -r \"test_rsc\" -a \"start\" "+self.action_timeout+" -o "
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:start rc:ok op_status:complete\" ")
test.add_cmd("-c exec -r \"test_rsc\" -a \"monitor\" -i \"100\" "+self.action_timeout+" -o "
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:ok op_status:complete\" ")
test.add_expected_fail_cmd("-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:ok op_status:complete\" "+self.action_timeout)
test.add_cmd_and_kill("rm -f @localstatedir@/run/Dummy-test_rsc.state", "-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:not running op_status:complete\" -t 6000")
test.add_cmd("-c cancel -r \"test_rsc\" -a \"monitor\" -i \"100\" -t \"3000\" "
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:not running op_status:Cancelled\" ")
test.add_expected_fail_cmd("-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:not running op_status:complete\" "+self.action_timeout)
test.add_expected_fail_cmd("-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:ok op_status:complete\" "+self.action_timeout)
test.add_cmd("-c unregister_rsc -r \"test_rsc\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:unregister rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
### monitor fail for systemd resource ###
if "systemd" in self.rsc_classes:
test = self.new_test("monitor_fail_systemd", "Force systemd monitor to fail, verify failure is reported..")
test.add_cmd("-c register_rsc -r \"test_rsc\" -C systemd -T lrmd_dummy_daemon "+self.action_timeout+
"-l \"NEW_EVENT event_type:register rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
test.add_cmd("-c exec -r \"test_rsc\" -a \"start\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:start rc:ok op_status:complete\" ")
test.add_cmd("-c exec -r \"test_rsc\" -a \"start\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:start rc:ok op_status:complete\" ")
test.add_cmd("-c exec -r \"test_rsc\" -a \"monitor\" -i \"100\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:ok op_status:complete\" ")
test.add_cmd("-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:ok op_status:complete\" "+self.action_timeout)
test.add_cmd("-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:ok op_status:complete\" "+self.action_timeout)
test.add_cmd_and_kill("killall -9 -q lrmd_dummy_daemon", "-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:not running op_status:complete\" -t 8000")
test.add_cmd("-c cancel -r \"test_rsc\" -a \"monitor\" -i \"100\" -t \"3000\" "
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:not running op_status:Cancelled\" ")
test.add_expected_fail_cmd("-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:not running op_status:complete\" "+self.action_timeout)
test.add_expected_fail_cmd("-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:ok op_status:complete\" "+self.action_timeout)
test.add_cmd("-c unregister_rsc -r \"test_rsc\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:unregister rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
### monitor fail for upstart resource ###
if "upstart" in self.rsc_classes:
test = self.new_test("monitor_fail_upstart", "Force upstart monitor to fail, verify failure is reported..")
test.add_cmd("-c register_rsc -r \"test_rsc\" -C upstart -T lrmd_dummy_daemon "+self.action_timeout+
"-l \"NEW_EVENT event_type:register rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
test.add_cmd("-c exec -r \"test_rsc\" -a \"start\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:start rc:ok op_status:complete\" ")
test.add_cmd("-c exec -r \"test_rsc\" -a \"start\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:start rc:ok op_status:complete\" ")
test.add_cmd("-c exec -r \"test_rsc\" -a \"monitor\" -i \"100\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:ok op_status:complete\" ")
test.add_cmd("-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:ok op_status:complete\" "+self.action_timeout)
test.add_cmd("-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:ok op_status:complete\" "+self.action_timeout)
test.add_cmd_and_kill("killall -9 -q dd", "-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:not running op_status:complete\" -t 8000")
test.add_cmd("-c cancel -r \"test_rsc\" -a \"monitor\" -i \"100\" -t \"3000\" "
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:not running op_status:Cancelled\" ")
test.add_expected_fail_cmd("-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:not running op_status:complete\" "+self.action_timeout)
test.add_expected_fail_cmd("-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:ok op_status:complete\" "+self.action_timeout)
test.add_cmd("-c unregister_rsc -r \"test_rsc\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:unregister rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
### Cancel non-existent operation on a resource ###
test = self.new_test("cancel_non_existent_op", "Attempt to cancel the wrong monitor operation, verify expected failure")
test.add_cmd("-c register_rsc -r \"test_rsc\" -C \"ocf\" -P \"pacemaker\" -T \"Dummy\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:register rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
test.add_cmd("-c exec -r \"test_rsc\" -a \"start\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:start rc:ok op_status:complete\" ")
test.add_cmd("-c exec -r \"test_rsc\" -a \"start\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:start rc:ok op_status:complete\" ")
test.add_cmd("-c exec -r \"test_rsc\" -a \"monitor\" -i \"100\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:ok op_status:complete\" ")
test.add_cmd("-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:ok op_status:complete\" "+self.action_timeout)
test.add_expected_fail_cmd("-c cancel -r test_rsc -a \"monitor\" -i 1234 -t \"3000\" " ### interval is wrong, should fail
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:not running op_status:Cancelled\" ")
test.add_expected_fail_cmd("-c cancel -r test_rsc -a stop -i 100 -t \"3000\" " ### action name is wrong, should fail
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:not running op_status:Cancelled\" ")
test.add_cmd("-c unregister_rsc -r \"test_rsc\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:unregister rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
### Attempt to invoke non-existent rsc id ###
test = self.new_test("invoke_non_existent_rsc", "Attempt to perform operations on a non-existent rsc id.")
test.add_expected_fail_cmd("-c exec -r \"test_rsc\" -a \"start\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:start rc:unknown error op_status:complete\" ")
test.add_expected_fail_cmd("-c exec -r test_rsc -a stop "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:stop rc:ok op_status:complete\" ")
test.add_expected_fail_cmd("-c exec -r test_rsc -a monitor -i 3000 "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:ok op_status:complete\" ")
test.add_expected_fail_cmd("-c cancel -r test_rsc -a start "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:start rc:ok op_status:Cancelled\" ")
test.add_cmd("-c unregister_rsc -r \"test_rsc\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:unregister rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
### Register and start a resource that doesn't exist, systemd ###
if "systemd" in self.rsc_classes:
test = self.new_test("start_uninstalled_systemd", "Register uninstalled systemd agent, try to start, verify expected failure")
test.add_cmd("-c register_rsc -r \"test_rsc\" -C systemd -T this_is_fake1234 "+self.action_timeout+
"-l \"NEW_EVENT event_type:register rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
test.add_cmd("-c exec -r \"test_rsc\" -a \"start\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:start rc:not installed op_status:Not installed\" ")
test.add_cmd("-c unregister_rsc -r \"test_rsc\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:unregister rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
if "upstart" in self.rsc_classes:
test = self.new_test("start_uninstalled_upstart", "Register uninstalled upstart agent, try to start, verify expected failure")
test.add_cmd("-c register_rsc -r \"test_rsc\" -C upstart -T this_is_fake1234 "+self.action_timeout+
"-l \"NEW_EVENT event_type:register rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
test.add_cmd("-c exec -r \"test_rsc\" -a \"start\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:start rc:not installed op_status:Not installed\" ")
test.add_cmd("-c unregister_rsc -r \"test_rsc\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:unregister rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
### Register and start a resource that doesn't exist, ocf ###
test = self.new_test("start_uninstalled_ocf", "Register uninstalled ocf agent, try to start, verify expected failure.")
test.add_cmd("-c register_rsc -r \"test_rsc\" -C ocf -P pacemaker -T this_is_fake1234 "+self.action_timeout+
"-l \"NEW_EVENT event_type:register rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
test.add_cmd("-c exec -r \"test_rsc\" -a \"start\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:start rc:not installed op_status:Not installed\" ")
test.add_cmd("-c unregister_rsc -r \"test_rsc\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:unregister rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
### Register ocf with non-existent provider ###
test = self.new_test("start_ocf_bad_provider", "Register ocf agent with a non-existent provider, verify expected failure.")
test.add_cmd("-c register_rsc -r \"test_rsc\" -C ocf -P pancakes -T Dummy "+self.action_timeout+
"-l \"NEW_EVENT event_type:register rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
test.add_cmd("-c exec -r \"test_rsc\" -a \"start\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:start rc:not installed op_status:Not installed\" ")
test.add_cmd("-c unregister_rsc -r \"test_rsc\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:unregister rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
### Register ocf with empty provider field ###
test = self.new_test("start_ocf_no_provider", "Register ocf agent with a no provider, verify expected failure.")
test.add_expected_fail_cmd("-c register_rsc -r \"test_rsc\" -C ocf -T Dummy "+self.action_timeout+
"-l \"NEW_EVENT event_type:register rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
test.add_expected_fail_cmd("-c exec -r \"test_rsc\" -a \"start\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:start rc:ok op_status:Error\" ")
test.add_cmd("-c unregister_rsc -r \"test_rsc\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:unregister rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
+ ### stress tests ###
+ def build_stress_tests(self):
+ timeout = "-t 20000"
+ iterations = 25
+
+ test = self.new_test("ocf_stress", "Verify systemd dbus connection works under load")
+ for i in range(iterations):
+ test.add_cmd("-c register_rsc -r rsc_%s %s -C ocf -P heartbeat -T Dummy -l \"NEW_EVENT event_type:register rsc_id:rsc_%s action:none rc:ok op_status:complete\"" % (i, timeout, i))
+ test.add_cmd("-c exec -r rsc_%s -a start %s -l \"NEW_EVENT event_type:exec_complete rsc_id:rsc_%s action:start rc:ok op_status:complete\"" % (i, timeout, i))
+ test.add_cmd("-c exec -r rsc_%s -a monitor %s -i 1000 -l \"NEW_EVENT event_type:exec_complete rsc_id:rsc_%s action:monitor rc:ok op_status:complete\"" % (i, timeout, i))
+ for i in range(iterations):
+ test.add_cmd("-c exec -r rsc_%s -a stop %s -l \"NEW_EVENT event_type:exec_complete rsc_id:rsc_%s action:stop rc:ok op_status:complete\"" % (i, timeout, i))
+ test.add_cmd("-c unregister_rsc -r rsc_%s %s -l \"NEW_EVENT event_type:unregister rsc_id:rsc_%s action:none rc:ok op_status:complete\"" % (i, timeout, i))
+
+
+ if "systemd" in self.rsc_classes:
+ test = self.new_test("systemd_stress", "Verify systemd dbus connection works under load")
+ for i in range(iterations):
+ test.add_cmd("-c register_rsc -r rsc_%s %s -C systemd -T lrmd_dummy_daemon -l \"NEW_EVENT event_type:register rsc_id:rsc_%s action:none rc:ok op_status:complete\"" % (i, timeout, i))
+ test.add_cmd("-c exec -r rsc_%s -a start %s -l \"NEW_EVENT event_type:exec_complete rsc_id:rsc_%s action:start rc:ok op_status:complete\"" % (i, timeout, i))
+ test.add_cmd("-c exec -r rsc_%s -a monitor %s -i 1000 -l \"NEW_EVENT event_type:exec_complete rsc_id:rsc_%s action:monitor rc:ok op_status:complete\"" % (i, timeout, i))
+
+ for i in range(iterations):
+ test.add_cmd("-c exec -r rsc_%s -a stop %s -l \"NEW_EVENT event_type:exec_complete rsc_id:rsc_%s action:stop rc:ok op_status:complete\"" % (i, timeout, i))
+ test.add_cmd("-c unregister_rsc -r rsc_%s %s -l \"NEW_EVENT event_type:unregister rsc_id:rsc_%s action:none rc:ok op_status:complete\"" % (i, timeout, i))
+
+
### These are tests that target specific cases ###
def build_custom_tests(self):
### verify resource temporary folder is created and used by heartbeat agents. ###
test = self.new_test("rsc_tmp_dir", "Verify creation and use of rsc temporary state directory")
test.add_sys_cmd("ls", "-al @CRM_RSCTMP_DIR@")
test.add_cmd("-c register_rsc -r test_rsc -P heartbeat -C ocf -T Dummy "
"-l \"NEW_EVENT event_type:register rsc_id:test_rsc action:none rc:ok op_status:complete\" "+self.action_timeout)
test.add_cmd("-c exec -r test_rsc -a start -t 4000")
test.add_sys_cmd("ls", "-al @CRM_RSCTMP_DIR@")
test.add_sys_cmd("ls", "@CRM_RSCTMP_DIR@/Dummy-test_rsc.state")
test.add_cmd("-c exec -r test_rsc -a stop -t 4000")
test.add_cmd("-c unregister_rsc -r test_rsc "+self.action_timeout+
"-l \"NEW_EVENT event_type:unregister rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
### start delay then stop test ###
test = self.new_test("start_delay", "Verify start delay works as expected.")
test.add_cmd("-c register_rsc -r test_rsc -P pacemaker -C ocf -T Dummy "
"-l \"NEW_EVENT event_type:register rsc_id:test_rsc action:none rc:ok op_status:complete\" "+self.action_timeout)
test.add_cmd("-c exec -r test_rsc -s 6000 -a start -w -t 6000")
test.add_expected_fail_cmd("-l "
"\"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:start rc:ok op_status:complete\" -t 2000")
test.add_cmd("-l "
"\"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:start rc:ok op_status:complete\" -t 6000")
test.add_cmd("-c exec -r test_rsc -a stop "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:stop rc:ok op_status:complete\" ")
test.add_cmd("-c unregister_rsc -r test_rsc "+self.action_timeout+
"-l \"NEW_EVENT event_type:unregister rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
### start delay, but cancel before it gets a chance to start. ###
test = self.new_test("start_delay_cancel", "Using start_delay, start a rsc, but cancel the start op before execution.")
test.add_cmd("-c register_rsc -r test_rsc -P pacemaker -C ocf -T Dummy "
"-l \"NEW_EVENT event_type:register rsc_id:test_rsc action:none rc:ok op_status:complete\" "+self.action_timeout)
test.add_cmd("-c exec -r test_rsc -s 5000 -a start -w -t 4000")
test.add_cmd("-c cancel -r test_rsc -a start "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:start rc:ok op_status:Cancelled\" ")
test.add_expected_fail_cmd("-l "
"\"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:start rc:ok op_status:complete\" -t 5000")
test.add_cmd("-c unregister_rsc -r test_rsc "+self.action_timeout+
"-l \"NEW_EVENT event_type:unregister rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
### Register a bunch of resources, verify we can get info on them ###
test = self.new_test("verify_get_rsc_info", "Register multiple resources, verify retrieval of rsc info.")
if "systemd" in self.rsc_classes:
test.add_cmd("-c register_rsc -r rsc1 -C systemd -T lrmd_dummy_daemon "+self.action_timeout)
test.add_cmd("-c get_rsc_info -r rsc1 ")
test.add_cmd("-c unregister_rsc -r rsc1 "+self.action_timeout)
test.add_expected_fail_cmd("-c get_rsc_info -r rsc1 ")
if "upstart" in self.rsc_classes:
test.add_cmd("-c register_rsc -r rsc1 -C upstart -T lrmd_dummy_daemon "+self.action_timeout)
test.add_cmd("-c get_rsc_info -r rsc1 ")
test.add_cmd("-c unregister_rsc -r rsc1 "+self.action_timeout)
test.add_expected_fail_cmd("-c get_rsc_info -r rsc1 ")
test.add_cmd("-c register_rsc -r rsc2 -C ocf -T Dummy -P pacemaker "+self.action_timeout)
test.add_cmd("-c get_rsc_info -r rsc2 ")
test.add_cmd("-c unregister_rsc -r rsc2 "+self.action_timeout)
test.add_expected_fail_cmd("-c get_rsc_info -r rsc2 ")
### Register duplicate, verify only one entry exists and can still be removed.
test = self.new_test("duplicate_registration", "Register resource multiple times, verify only one entry exists and can be removed.")
test.add_cmd("-c register_rsc -r rsc2 -C ocf -T Dummy -P pacemaker "+self.action_timeout)
test.add_cmd_check_stdout("-c get_rsc_info -r rsc2 ", "id:rsc2 class:ocf provider:pacemaker type:Dummy")
test.add_cmd("-c register_rsc -r rsc2 -C ocf -T Dummy -P pacemaker "+self.action_timeout)
test.add_cmd_check_stdout("-c get_rsc_info -r rsc2 ", "id:rsc2 class:ocf provider:pacemaker type:Dummy")
test.add_cmd("-c register_rsc -r rsc2 -C ocf -T Stateful -P pacemaker "+self.action_timeout)
test.add_cmd_check_stdout("-c get_rsc_info -r rsc2 ", "id:rsc2 class:ocf provider:pacemaker type:Stateful")
test.add_cmd("-c unregister_rsc -r rsc2 "+self.action_timeout)
test.add_expected_fail_cmd("-c get_rsc_info -r rsc2 ")
### verify the option to only send notification to the original client. ###
test = self.new_test("notify_orig_client_only", "Verify option to only send notifications to the client originating the action.")
test.add_cmd("-c register_rsc -r \"test_rsc\" -C \"ocf\" -P \"pacemaker\" -T \"Dummy\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:register rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
test.add_cmd("-c exec -r \"test_rsc\" -a \"start\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:start rc:ok op_status:complete\" ")
test.add_cmd("-c exec -r \"test_rsc\" -a \"monitor\" -i \"100\" "+self.action_timeout+" -n "
"-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:ok op_status:complete\" ")
# this will fail because the monitor notifications should only go to the original caller, which no longer exists.
test.add_expected_fail_cmd("-l \"NEW_EVENT event_type:exec_complete rsc_id:test_rsc action:monitor rc:ok op_status:complete\" "+self.action_timeout)
test.add_cmd("-c cancel -r \"test_rsc\" -a \"monitor\" -i \"100\" -t \"3000\" ")
test.add_cmd("-c unregister_rsc -r \"test_rsc\" "+self.action_timeout+
"-l \"NEW_EVENT event_type:unregister rsc_id:test_rsc action:none rc:ok op_status:complete\" ")
### get metadata ###
test = self.new_test("get_ocf_metadata", "Retrieve metadata for a resource")
test.add_cmd_check_stdout("-c metadata -C \"ocf\" -P \"pacemaker\" -T \"Dummy\""
,"resource-agent name=\"Dummy\"")
test.add_cmd("-c metadata -C \"ocf\" -P \"pacemaker\" -T \"Stateful\"")
test.add_expected_fail_cmd("-c metadata -P \"pacemaker\" -T \"Stateful\"")
test.add_expected_fail_cmd("-c metadata -C \"ocf\" -P \"pacemaker\" -T \"fake_agent\"")
### get metadata ###
test = self.new_test("get_lsb_metadata", "Retrieve metadata for a resource")
test.add_cmd_check_stdout("-c metadata -C \"lsb\" -T \"LSBDummy\""
,"resource-agent name='LSBDummy'")
### get stonith metadata ###
test = self.new_test("get_stonith_metadata", "Retrieve stonith metadata for a resource")
test.add_cmd_check_stdout("-c metadata -C \"stonith\" -P \"pacemaker\" -T \"fence_dummy_monitor\"",
"resource-agent name=\"fence_dummy_monitor\"")
### get metadata ###
if "systemd" in self.rsc_classes:
test = self.new_test("get_systemd_metadata", "Retrieve metadata for a resource")
test.add_cmd_check_stdout("-c metadata -C \"systemd\" -T \"lrmd_dummy_daemon\""
,"resource-agent name=\"lrmd_dummy_daemon\"")
### get metadata ###
if "upstart" in self.rsc_classes:
test = self.new_test("get_upstart_metadata", "Retrieve metadata for a resource")
test.add_cmd_check_stdout("-c metadata -C \"upstart\" -T \"lrmd_dummy_daemon\""
,"resource-agent name=\"lrmd_dummy_daemon\"")
### get ocf providers ###
test = self.new_test("list_ocf_providers", "Retrieve list of available resource providers, verifies pacemaker is a provider.")
test.add_cmd_check_stdout("-c list_ocf_providers ", "pacemaker")
test.add_cmd_check_stdout("-c list_ocf_providers -T ping", "pacemaker")
### Verify agents only exist in their lists ###
test = self.new_test("verify_agent_lists", "Verify the agent lists contain the right data.")
test.add_cmd_check_stdout("-c list_agents ", "Stateful") ### ocf ###
test.add_cmd_check_stdout("-c list_agents -C ocf", "Stateful")
test.add_cmd_check_stdout("-c list_agents -C lsb", "", "Stateful") ### should not exist
test.add_cmd_check_stdout("-c list_agents -C service", "", "Stateful") ### should not exist
test.add_cmd_check_stdout("-c list_agents ", "LSBDummy") ### init.d ###
test.add_cmd_check_stdout("-c list_agents -C lsb", "LSBDummy")
test.add_cmd_check_stdout("-c list_agents -C service", "LSBDummy")
test.add_cmd_check_stdout("-c list_agents -C ocf", "", "lrmd_dummy_daemon") ### should not exist
test.add_cmd_check_stdout("-c list_agents -C ocf", "", "lrmd_dummy_daemon") ### should not exist
test.add_cmd_check_stdout("-c list_agents -C lsb", "", "fence_dummy_monitor") ### should not exist
test.add_cmd_check_stdout("-c list_agents -C service", "", "fence_dummy_monitor") ### should not exist
test.add_cmd_check_stdout("-c list_agents -C ocf", "", "fence_dummy_monitor") ### should not exist
if "systemd" in self.rsc_classes:
test.add_cmd_check_stdout("-c list_agents ", "lrmd_dummy_daemon") ### systemd ###
test.add_cmd_check_stdout("-c list_agents -C service", "LSBDummy")
test.add_cmd_check_stdout("-c list_agents -C systemd", "", "Stateful") ### should not exist
test.add_cmd_check_stdout("-c list_agents -C systemd", "lrmd_dummy_daemon")
test.add_cmd_check_stdout("-c list_agents -C systemd", "", "fence_dummy_monitor") ### should not exist
if "upstart" in self.rsc_classes:
test.add_cmd_check_stdout("-c list_agents ", "lrmd_dummy_daemon") ### upstart ###
test.add_cmd_check_stdout("-c list_agents -C service", "LSBDummy")
test.add_cmd_check_stdout("-c list_agents -C upstart", "", "Stateful") ### should not exist
test.add_cmd_check_stdout("-c list_agents -C upstart", "lrmd_dummy_daemon")
test.add_cmd_check_stdout("-c list_agents -C upstart", "", "fence_dummy_monitor") ### should not exist
if "stonith" in self.rsc_classes:
test.add_cmd_check_stdout("-c list_agents -C stonith", "fence_dummy_monitor") ### stonith ###
test.add_cmd_check_stdout("-c list_agents -C stonith", "", "lrmd_dummy_daemon") ### should not exist
test.add_cmd_check_stdout("-c list_agents -C stonith", "", "Stateful") ### should not exist
test.add_cmd_check_stdout("-c list_agents ", "fence_dummy_monitor")
def print_list(self):
print "\n==== %d TESTS FOUND ====" % (len(self.tests))
print "%35s - %s" % ("TEST NAME", "TEST DESCRIPTION")
print "%35s - %s" % ("--------------------", "--------------------")
for test in self.tests:
print "%35s - %s" % (test.name, test.description)
print "==== END OF LIST ====\n"
def run_single(self, name):
for test in self.tests:
if test.name == name:
test.run()
break;
def run_tests_matching(self, pattern):
for test in self.tests:
if test.name.count(pattern) != 0:
test.run()
def run_tests(self):
for test in self.tests:
test.run()
def exit(self):
for test in self.tests:
if test.executed == 0:
continue
if test.get_exitcode() != 0:
sys.exit(-1)
sys.exit(0);
def print_results(self):
failures = 0;
success = 0;
print "\n\n======= FINAL RESULTS =========="
print "\n--- FAILURE RESULTS:"
for test in self.tests:
if test.executed == 0:
continue
if test.get_exitcode() != 0:
failures = failures + 1
test.print_result(" ")
else:
success = success + 1
if failures == 0:
print " None"
print "\n--- TOTALS\n Pass:%d\n Fail:%d\n" % (success, failures)
class TestOptions:
def __init__(self):
self.options = {}
self.options['list-tests'] = 0
self.options['run-all'] = 1
self.options['run-only'] = ""
self.options['run-only-pattern'] = ""
self.options['verbose'] = 0
self.options['invalid-arg'] = ""
self.options['show-usage'] = 0
self.options['pacemaker-remote'] = 0
def build_options(self, argv):
args = argv[1:]
skip = 0
for i in range(0, len(args)):
if skip:
skip = 0
continue
elif args[i] == "-h" or args[i] == "--help":
self.options['show-usage'] = 1
elif args[i] == "-l" or args[i] == "--list-tests":
self.options['list-tests'] = 1
elif args[i] == "-V" or args[i] == "--verbose":
self.options['verbose'] = 1
elif args[i] == "-R" or args[i] == "--pacemaker-remote":
self.options['pacemaker-remote'] = 1
elif args[i] == "-r" or args[i] == "--run-only":
self.options['run-only'] = args[i+1]
skip = 1
elif args[i] == "-p" or args[i] == "--run-only-pattern":
self.options['run-only-pattern'] = args[i+1]
skip = 1
def show_usage(self):
print "usage: " + sys.argv[0] + " [options]"
print "If no options are provided, all tests will run"
print "Options:"
print "\t [--help | -h] Show usage"
print "\t [--list-tests | -l] Print out all registered tests."
print "\t [--run-only | -r 'testname'] Run a specific test"
print "\t [--verbose | -V] Verbose output"
print "\t [--pacemaker-remote | -R Test pacemaker-remote binary instead of lrmd."
print "\t [--run-only-pattern | -p 'string'] Run only tests containing the string value"
print "\n\tExample: Run only the test 'start_top'"
print "\t\t python ./regression.py --run-only start_stop"
print "\n\tExample: Run only the tests with the string 'systemd' present in them"
print "\t\t python ./regression.py --run-only-pattern systemd"
def main(argv):
o = TestOptions()
o.build_options(argv)
tests = Tests(o.options['verbose'], o.options['pacemaker-remote'])
tests.build_generic_tests()
tests.build_multi_rsc_tests()
tests.build_negative_tests()
tests.build_custom_tests()
+ tests.build_stress_tests()
tests.setup_test_environment()
print "Starting ..."
if o.options['list-tests']:
tests.print_list()
elif o.options['show-usage']:
o.show_usage()
elif o.options['run-only-pattern'] != "":
tests.run_tests_matching(o.options['run-only-pattern'])
tests.print_results()
elif o.options['run-only'] != "":
tests.run_single(o.options['run-only'])
tests.print_results()
else:
tests.run_tests()
tests.print_results()
tests.cleanup_test_environment()
tests.exit()
if __name__=="__main__":
main(sys.argv)
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Wed, Jun 25, 4:12 AM (1 d, 10 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1952105
Default Alt Text
(98 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment