fence-virt/server/libvirt-qmf.cpp
Lon Hohberger 961cc3ed7f Update libvirt-qmf plugin and docs
Resolves: rhbz#753974

Signed-off-by: Lon Hohberger <lon@users.sourceforge.net>
2012-02-08 15:46:50 -05:00

496 lines
10 KiB
C++

//
// Copyright Red Hat, Inc. 2009
//
// 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, 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; see the file COPYING. If not, write to the
// Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
// MA 02139, USA.
//
// Author: Lon Hohberger <lhh at redhat.com>
//
#include <stdio.h>
#include <simpleconfig.h>
#include <static_map.h>
#include <sys/types.h>
#include <stdint.h>
#include <time.h>
#include <server_plugin.h>
#include <string.h>
#include <malloc.h>
#include <errno.h>
#include <string>
#include <sstream>
#include <iostream>
#include "uuid-test.h"
#include <xvm.h>
#include <qpid/types/Variant.h>
#include <qpid/messaging/Connection.h>
#include <qpid/console/Object.h>
#include <qmf/ConsoleSession.h>
#include <qmf/ConsoleEvent.h>
#define NAME "libvirt-qmf"
#define VERSION "0.2"
#define MAGIC 0x1e01017a
struct lq_info {
int magic;
int port;
char *host;
char *username;
char *service;
int use_gssapi;
};
#define VALIDATE(arg) \
do {\
if (!arg || ((struct lq_info *)arg)->magic != MAGIC) { \
errno = EINVAL;\
return -1; \
} \
} while(0)
static qmf::ConsoleSession
lq_open_session(struct lq_info *info)
{
qmf::ConsoleSession session;
std::stringstream url;
url << info->host << ":" << info->port;
qpid::types::Variant::Map options;
if (info->username) {
options["username"] = info->username;
}
if (info->service) {
options["sasl-service"] = info->service;
}
if (info->use_gssapi) {
options["sasl-mechanism"] = "GSSAPI";
}
try {
qpid::messaging::Connection connection(url.str(), options);
connection.open();
if (!connection.isOpen()) {
std::cout << "Error connecting." << std::endl;
} else {
session = qmf::ConsoleSession(connection);
std::stringstream filter;
filter << "[or, "
"[eq, _product, [quote, 'libvirt-qmf']], "
"[eq, _product, [quote, 'libvirt-qpid']]"
"]";
session.setAgentFilter(filter.str());
session.open();
}
}
catch (qpid::messaging::TransportFailure ex) {
std::cout << "Error establishing session: " << ex.what() << std::endl;
}
return session;
}
static qmf::ConsoleEvent
queryDomain(qmf::Agent& agent)
{
std::string query;
if (agent.getProduct() == "libvirt-qmf") {
query = "{class: Domain, package: 'org.libvirt'}";
} else {
query = "{class: domain, package: 'com.redhat.libvirt'}";
}
return agent.query(query);
}
int
do_lq_request(struct lq_info *info, const char *vm_name,
const char *action)
{
std::string vm_state;
const char *property = "name";
if (is_uuid(vm_name) == 1) {
property = "uuid";
}
qmf::ConsoleSession session(lq_open_session(info));
if (!session.isValid()) {
std::cout << "Invalid session." << std::endl;
return 1;
}
qmf::Agent agent;
qmf::Data domain;
int result;
unsigned tries = 0;
bool found = false;
while (++tries < 10 && !found) {
sleep(1);
uint32_t numAgents = session.getAgentCount();
for (unsigned a = 0; !found && a < numAgents; a++) {
agent = session.getAgent(a);
qmf::ConsoleEvent event(queryDomain(agent));
uint32_t numDomains = event.getDataCount();
for (unsigned d = 0; !found && d < numDomains; d++) {
domain = event.getData(d);
qpid::types::Variant prop;
try {
prop = domain.getProperty(property);
} catch (qmf::KeyNotFound e) {
std::cout << e.what() << " - skipping" << std::endl;
continue;
}
if (prop.asString() != vm_name) {
continue;
}
found = true;
}
}
}
if (!found) {
result = 1;
goto out;
}
vm_state = domain.getProperty("state").asString();
std::cout << vm_name << " " << vm_state << std::endl;
int r;
if (vm_state == "running" ||
vm_state == "idle" ||
vm_state == "paused" ||
vm_state == "no state") {
r = RESP_OFF;
} else {
r = 0;
}
if (strcasecmp(action, "state") == 0) {
result = r;
goto out;
}
result = 1;
if (!r && strcasecmp(action, "destroy") == 0) {
std::cout << "Domain is inactive; nothing to do" << std::endl;
result = 0;
goto out;
}
if (r && strcasecmp(action, "create") == 0) {
std::cout << "Domain is active; nothing to do" << std::endl;
result = 0;
goto out;
}
{
qmf::ConsoleEvent response;
response = agent.callMethod(action,
qpid::types::Variant::Map(),
domain.getAddr());
if (response.getType() == qmf::CONSOLE_EXCEPTION) {
std::string errorText;
if (response.getDataCount()) {
qmf::Data responseData(response.getData(0));
qpid::types::Variant code(responseData.getProperty("error_code"));
if (code.getType() == qpid::types::VAR_INT32) {
result = responseData.getProperty("error_code").asInt32();
} else {
result = 7; // Exception
}
qpid::types::Variant text(responseData.getProperty("error_text"));
if (text.getType() != qpid::types::VAR_VOID) {
errorText = text.asString();
}
} else {
result = 7; // Exception
}
std::cout << "Response: " << result;
if (errorText.length()) {
std::cout << " (" << errorText << ")";
}
std::cout << std::endl;
} else { // Success
result = 0;
}
}
out:
session.close();
return result;
}
static int
lq_null(const char *vm_name, void *priv)
{
VALIDATE(priv);
printf("[libvirt-qmf] NULL operation on %s\n", vm_name);
return 1;
}
static int
lq_off(const char *vm_name, const char *src, uint32_t seqno, void *priv)
{
VALIDATE(priv);
printf("[libvirt-qmf] OFF operation on %s\n", vm_name);
return do_lq_request((lq_info *)priv, vm_name, "destroy");
return 1;
}
static int
lq_on(const char *vm_name, const char *src, uint32_t seqno, void *priv)
{
VALIDATE(priv);
printf("[libvirt-qmf] ON operation on %s\n", vm_name);
return do_lq_request((lq_info *)priv, vm_name, "create");
}
static int
lq_devstatus(void *priv)
{
VALIDATE(priv);
printf("[libvirt-qmf] Device status\n");
return 0;
}
static int
lq_status(const char *vm_name, void *priv)
{
VALIDATE(priv);
printf("[libvirt-qmf] STATUS operation on %s\n", vm_name);
return do_lq_request((lq_info *)priv, vm_name, "state");
}
static int
lq_reboot(const char *vm_name, const char *src, uint32_t seqno, void *priv)
{
VALIDATE(priv);
printf("[libvirt-qmf] REBOOT operation on %s\n", vm_name);
if (lq_off(vm_name, src, seqno, priv) != 0)
return 1;
sleep(1);
lq_on(vm_name, src, seqno, priv);
return 0;
}
static int
lq_hostlist(hostlist_callback callback, void *arg, void *priv)
{
VALIDATE(priv);
printf("[libvirt-qmf] HOSTLIST operation\n");
qmf::ConsoleSession session(lq_open_session((struct lq_info *)priv));
if (!session.isValid()) {
return 1;
}
unsigned tries = 0;
qmf::ConsoleEvent event;
uint32_t numDomains = 0;
while (++tries < 10 && !numDomains) {
sleep(1);
uint32_t numAgents = session.getAgentCount();
for (unsigned a = 0; a < numAgents; a++) {
qmf::Agent agent(session.getAgent(a));
event = queryDomain(agent);
numDomains = event.getDataCount();
if (numDomains >= 1) {
break;
}
}
}
for (unsigned d = 0; d < numDomains; d++) {
qmf::Data domain = event.getData(d);
std::string vm_name, vm_uuid, vm_state_str;
try {
vm_name = domain.getProperty("name").asString();
vm_uuid = domain.getProperty("uuid").asString();
vm_state_str = domain.getProperty("state").asString();
} catch (qmf::KeyNotFound e) {
std::cout << e.what() << " - skipping" << std::endl;
continue;
}
int vm_state;
if (!strcasecmp(vm_state_str.c_str(), "shutoff")) {
vm_state = 0;
} else {
vm_state = 1;
}
callback(vm_name.c_str(), vm_uuid.c_str(), vm_state, arg);
}
session.close();
return 0;
}
static int
lq_init(backend_context_t *c, config_object_t *config)
{
char value[256];
struct lq_info *info = NULL;
info = (lq_info *)malloc(sizeof(*info));
if (!info)
return -1;
memset(info, 0, sizeof(*info));
info->port = 5672; /* Actually match default qpid port */
if(sc_get(config, "backends/libvirt-qmf/@host",
value, sizeof(value))==0){
printf("\n\nHOST = %s\n\n",value);
info->host = strdup(value);
if (!info->host) {
goto out_fail;
}
} else {
info->host = strdup("127.0.0.1");
}
if(sc_get(config, "backends/libvirt-qmf/@port",
value, sizeof(value)-1)==0){
printf("\n\nPORT = %d\n\n",atoi(value));
info->port = atoi(value);
}
if(sc_get(config, "backends/libvirt-qmf/@username",
value, sizeof(value))==0){
printf("\n\nUSERNAME = %s\n\n",value);
info->username = strdup(value);
if (!info->username) {
goto out_fail;
}
}
if(sc_get(config, "backends/libvirt-qmf/@service",
value, sizeof(value))==0){
printf("\n\nSERVICE = %s\n\n",value);
info->service = strdup(value);
if (!info->service) {
goto out_fail;
}
}
if(sc_get(config, "backends/libvirt-qmf/@gssapi",
value, sizeof(value)-1)==0){
printf("\n\nGSSAPI = %d\n\n",atoi(value));
if (atoi(value) > 0) {
info->use_gssapi = 1;
}
}
info->magic = MAGIC;
*c = (void *)info;
return 0;
out_fail:
free(info->service);
free(info->username);
free(info->host);
free(info);
return -1;
}
static int
lq_shutdown(backend_context_t c)
{
struct lq_info *info = (struct lq_info *)c;
VALIDATE(info);
info->magic = 0;
free(info->service);
free(info->username);
free(info->host);
free(info);
return 0;
}
static fence_callbacks_t lq_callbacks = {
lq_null, lq_off, lq_on, lq_reboot, lq_status, lq_devstatus,
lq_hostlist
};
static backend_plugin_t lq_plugin = {
NAME, VERSION, &lq_callbacks, lq_init, lq_shutdown
};
#ifdef _MODULE
extern "C" double
BACKEND_VER_SYM(void)
{
return PLUGIN_VERSION_BACKEND;
}
extern "C" const backend_plugin_t *
BACKEND_INFO_SYM(void)
{
return &lq_plugin;
}
#else
static void __attribute__((constructor))
lq_register_plugin(void)
{
plugin_reg_backend(&lq_plugin);
}
#endif