From 4d7839abcec6bcff7f0b2be74d6083d468bac2ca Mon Sep 17 00:00:00 2001 From: root Date: Mon, 7 Dec 2009 12:55:48 -0500 Subject: [PATCH] Hostlist functionality for libvirt, libvirt-qpid Signed-off-by: root --- client/main.c | 3 +- client/mcast.c | 54 ++++++++++++++++++++++++++--- client/options.c | 2 ++ include/server_plugin.h | 8 +++++ include/xvm.h | 9 +++++ server/checkpoint.c | 13 ++++++- server/libvirt-qpid.cpp | 76 ++++++++++++++++++++++++++++++++++++++++- server/libvirt.c | 31 ++++++++++++++++- server/mcast.c | 68 ++++++++++++++++++++++++++++++++++++ server/null.c | 13 ++++++- 10 files changed, 268 insertions(+), 9 deletions(-) diff --git a/client/main.c b/client/main.c index dfaf0d3..ba41184 100644 --- a/client/main.c +++ b/client/main.c @@ -95,7 +95,8 @@ main(int argc, char **argv) args_print(&args); /* Additional validation here */ - if (!args.domain) { + if (!args.domain && (args.op != FENCE_DEVSTATUS && + args.op != FENCE_HOSTLIST)) { printf("No domain specified!\n"); args.flags |= F_ERR; } diff --git a/client/mcast.c b/client/mcast.c index e9c9ab7..2e602ce 100644 --- a/client/mcast.c +++ b/client/mcast.c @@ -54,6 +54,7 @@ #include "tcp.h" #include "mcast.h" #include "debug.h" +#include "fdops.h" static int @@ -86,6 +87,43 @@ tcp_wait_connect(int lfd, int retry_tenths) } +void +do_read_hostlist(int fd, int timeout) +{ + host_state_t hinfo; + fd_set rfds; + struct timeval tv; + int ret; + + do { + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + tv.tv_sec = timeout; + tv.tv_usec = 0; + + ret = _select_retry(fd+1, &rfds, NULL, NULL, &tv); + if (ret == 0) { + printf("Timed out!\n"); + break; + } + + ret = _read_retry(fd, &hinfo, sizeof(hinfo), &tv); + if (ret < sizeof(hinfo)) { + printf("Bad read!\n"); + break; + } + + if (strlen((char *)hinfo.uuid) == 0 && + strlen((char *)hinfo.domain) == 0) + break; + + printf("%-20.20s %s %s\n", hinfo.domain, hinfo.uuid, + (hinfo.state == 0) ? "off" : "on"); + + } while (1); +} + + static int tcp_exchange(int fd, fence_auth_type_t auth, void *key, size_t key_len, int timeout) @@ -118,12 +156,18 @@ tcp_exchange(int fd, fence_auth_type_t auth, void *key, ret = 1; dbg_printf(3, "Waiting for return value from XVM host\n"); - if (select(fd + 1, &rfds, NULL, NULL, &tv) <= 0) + if (_select_retry(fd + 1, &rfds, NULL, NULL, &tv) <= 0) return -1; /* Read return code */ - if (read(fd, &ret, 1) < 0) + if (_read_retry(fd, &ret, 1, &tv) < 0) ret = 1; + + if (ret == (char)253) /* hostlist */ { + do_read_hostlist(fd, timeout); + ret = 0; + } + close(fd); if (ret == 0) @@ -178,8 +222,10 @@ send_multicast_packets(ip_list_t *ipl, fence_virt_args_t *args, /* Build our packet */ memset(&freq, 0, sizeof(freq)); - strncpy((char *)freq.domain, args->domain, - sizeof(freq.domain)); + if (args->domain && strlen((char *)args->domain)) { + strncpy((char *)freq.domain, args->domain, + sizeof(freq.domain)); + } freq.request = args->op; freq.hashtype = args->net.hash; freq.seqno = seqno; diff --git a/client/options.c b/client/options.c index ed49130..09b625b 100644 --- a/client/options.c +++ b/client/options.c @@ -192,6 +192,8 @@ assign_op(fence_virt_args_t *args, struct arg_info *arg, char *value) args->op = FENCE_STATUS; } else if (!strcasecmp(value, "devstatus")) { args->op = FENCE_DEVSTATUS; + } else if (!strcasecmp(value, "hostlist")) { + args->op = FENCE_HOSTLIST; } else { printf("Unsupported operation: %s\n", value); args->flags |= F_ERR; diff --git a/include/server_plugin.h b/include/server_plugin.h index bd43d5f..834d5b9 100644 --- a/include/server_plugin.h +++ b/include/server_plugin.h @@ -48,6 +48,13 @@ typedef int (*fence_status_callback)(const char *vm_name, is responding to requests. */ typedef int (*fence_devstatus_callback)(void *priv); +/* VMs available to fence. Returns 0 to caller if backend + is responding to requests and a host list can be produced */ +typedef int (*hostlist_callback)(const char *vm_name, const char *uuid, + int state, void *arg); +typedef int (*fence_hostlist_callback)(hostlist_callback cb, + void *arg, void *priv); + typedef int (*backend_init_fn)(backend_context_t *c, config_object_t *config); typedef int (*backend_cleanup_fn)(backend_context_t c); @@ -59,6 +66,7 @@ typedef struct _fence_callbacks { fence_reboot_callback reboot; fence_status_callback status; fence_devstatus_callback devstatus; + fence_hostlist_callback hostlist; } fence_callbacks_t; typedef struct backend_plugin { diff --git a/include/xvm.h b/include/xvm.h index 5836384..a46f030 100644 --- a/include/xvm.h +++ b/include/xvm.h @@ -85,6 +85,15 @@ typedef struct __attribute__ ((packed)) _fence_req { } fence_req_t; +/* for host list */ +typedef struct __attribute__ ((packed)) _host_info { + uint8_t domain[MAX_DOMAINNAME_LENGTH]; + uint8_t uuid[MAX_DOMAINNAME_LENGTH]; + uint8_t state; + uint8_t pad; +} host_state_t; + + #define DEFAULT_SERIAL_DEVICE "/dev/ttyS1" #define DEFAULT_SERIAL_SPEED "115200,8N1" #define SERIAL_MAGIC 0x61626261 /* endian doesn't matter */ diff --git a/server/checkpoint.c b/server/checkpoint.c index 1626b1d..0092dbf 100644 --- a/server/checkpoint.c +++ b/server/checkpoint.c @@ -651,6 +651,16 @@ checkpoint_reboot(const char *vm_name, uint32_t seqno, void *priv) } +static int +checkpoint_hostlist(hostlist_callback callback, void *arg, void *priv) +{ + VALIDATE(priv); + printf("[CKPT] HOSTLIST operation\n"); + + return 1; +} + + static int checkpoint_init(backend_context_t *c, config_object_t *config) { @@ -752,7 +762,8 @@ static fence_callbacks_t checkpoint_callbacks = { .on = checkpoint_on, .reboot = checkpoint_reboot, .status = checkpoint_status, - .devstatus = checkpoint_devstatus + .devstatus = checkpoint_devstatus, + .hostlist = checkpoint_hostlist }; static backend_plugin_t checkpoint_plugin = { diff --git a/server/libvirt-qpid.cpp b/server/libvirt-qpid.cpp index 737fcdf..ae5f06d 100644 --- a/server/libvirt-qpid.cpp +++ b/server/libvirt-qpid.cpp @@ -219,6 +219,79 @@ lq_reboot(const char *vm_name, uint32_t seqno, void *priv) } +static int +lq_hostlist(hostlist_callback callback, void *arg, void *priv) +{ + VALIDATE(priv); + + Broker *b = NULL; + ConnectionSettings cs; + SessionManager::NameVector names; + Object::Vector domains; + unsigned i, tries = 0; + const char *vm_name, *vm_uuid, *vm_state_str; + int vm_state = 0, ret = 1; + + printf("[libvirt-qpid] HOSTLIST operation\n"); + + cs.host = "127.0.0.1"; + cs.port = 5672; + + SessionManager::Settings s; + + s.rcvObjects = true; + s.rcvEvents = false; + s.rcvHeartbeats = false; + s.userBindings = false; + s.methodTimeout = 10; + s.getTimeout = 10; + + SessionManager sm(NULL, s); + // todo - authentication info! + + try { + b = sm.addBroker(cs); + } + catch (...) { + std::cout << "Error connecting.\n"; + return 1; + } + + while (tries < 10) { + sleep(1); + + sm.getObjects(domains, "domain", NULL, NULL); + + if (domains.size() >= 1) { + break; + } + } + + if (domains.size() < 1) + goto out; + + for (i = 0; i < domains.size(); i++) { + + vm_name = domains[i].attrString("name").c_str(); + vm_uuid = domains[i].attrString("uuid").c_str(); + vm_state_str = domains[i].attrString("state").c_str(); + + if (!strcasecmp(vm_state_str, "shutoff")) + vm_state = 0; + else + vm_state = 1; + + callback(vm_name, vm_uuid, vm_state, arg); + } + ret = 0; + +out: + sm.delBroker(b); + + return 0; +} + + static int lq_init(backend_context_t *c, config_object_t *config) { @@ -264,7 +337,8 @@ lq_shutdown(backend_context_t c) static fence_callbacks_t lq_callbacks = { - lq_null, lq_off, lq_on, lq_reboot, lq_status, lq_devstatus + lq_null, lq_off, lq_on, lq_reboot, lq_status, lq_devstatus, + lq_hostlist }; static backend_plugin_t lq_plugin = { diff --git a/server/libvirt.c b/server/libvirt.c index 2fc6cf6..ac7ff51 100644 --- a/server/libvirt.c +++ b/server/libvirt.c @@ -374,6 +374,34 @@ libvirt_reboot(const char *vm_name, uint32_t seqno, void *priv) return ret; } + +static int +libvirt_hostlist(hostlist_callback callback, void *arg, void *priv) +{ + struct libvirt_info *info = (struct libvirt_info *)priv; + virt_list_t *vl; + int x; + + dbg_printf(5, "%s\n", __FUNCTION__); + VALIDATE(info); + + vl = vl_get(info->vp, 1); + if (!vl) + return 1; + + for (x = 0; x < vl->vm_count; x++) { + printf("Sending %s\n", vl->vm_states[x].v_uuid); + callback(vl->vm_states[x].v_name, + vl->vm_states[x].v_uuid, + vl->vm_states[x].v_state.s_state, arg); + } + + vl_free(vl); + + return 0; +} + + static int libvirt_init(backend_context_t *c, config_object_t *config) { @@ -458,7 +486,8 @@ static fence_callbacks_t libvirt_callbacks = { .on = libvirt_on, .reboot = libvirt_reboot, .status = libvirt_status, - .devstatus = libvirt_devstatus + .devstatus = libvirt_devstatus, + .hostlist = libvirt_hostlist }; static backend_plugin_t libvirt_plugin = { diff --git a/server/mcast.c b/server/mcast.c index 031619f..eca03d6 100644 --- a/server/mcast.c +++ b/server/mcast.c @@ -54,6 +54,7 @@ #include "mcast.h" #include "tcp.h" #include "debug.h" +#include "fdops.h" #define NAME "multicast" #define VERSION "1.0" @@ -91,6 +92,11 @@ typedef struct _mcast_info { } mcast_info; +struct mcast_hostlist_arg { + int fd; +}; + + /* * See if we fenced this node recently (successfully) * If so, ignore the request for a few seconds. @@ -170,11 +176,66 @@ connect_tcp(fence_req_t *req, fence_auth_type_t auth, } +static int +mcast_hostlist(const char *vm_name, const char *vm_uuid, + int state, void *priv) +{ + struct mcast_hostlist_arg *arg = (struct mcast_hostlist_arg *)priv; + host_state_t hinfo; + struct timeval tv; + int ret; + + strncpy((char *)hinfo.domain, vm_name, sizeof(hinfo.domain)); + strncpy((char *)hinfo.uuid, vm_uuid, sizeof(hinfo.uuid)); + hinfo.state = state; + + tv.tv_sec = 1; + tv.tv_usec = 0; + ret = _write_retry(arg->fd, &hinfo, sizeof(hinfo), &tv); + if (ret == sizeof(hinfo)) + return 0; + return 1; +} + + +static int +mcast_hostlist_begin(int fd) +{ + struct timeval tv; + char val = (char)253; + + tv.tv_sec = 1; + tv.tv_usec = 0; + return _write_retry(fd, &val, 1, &tv); +} + + +static int +mcast_hostlist_end(int fd) +{ + host_state_t hinfo; + struct timeval tv; + int ret; + + printf("Sending terminator packet\n"); + + memset(&hinfo, 0, sizeof(hinfo)); + + tv.tv_sec = 1; + tv.tv_usec = 0; + ret = _write_retry(fd, &hinfo, sizeof(hinfo), &tv); + if (ret == sizeof(hinfo)) + return 0; + return 1; +} + + static int do_fence_request_tcp(fence_req_t *req, mcast_info *info) { int fd = -1; char response = 1; + struct mcast_hostlist_arg arg; fd = connect_tcp(req, info->args.auth, info->key, info->key_len); if (fd < 0) { @@ -182,6 +243,7 @@ do_fence_request_tcp(fence_req_t *req, mcast_info *info) strerror(errno)); goto out; } + arg.fd = fd; switch(req->request) { case FENCE_NULL: @@ -205,6 +267,12 @@ do_fence_request_tcp(fence_req_t *req, mcast_info *info) case FENCE_DEVSTATUS: response = info->cb->devstatus(info->priv); break; + case FENCE_HOSTLIST: + mcast_hostlist_begin(arg.fd); + response = info->cb->hostlist(mcast_hostlist, &arg, + info->priv); + mcast_hostlist_end(arg.fd); + break; } dbg_printf(3, "Sending response to caller...\n"); diff --git a/server/null.c b/server/null.c index f329444..3fcd971 100644 --- a/server/null.c +++ b/server/null.c @@ -112,6 +112,16 @@ null_reboot(const char *vm_name, uint32_t seqno, void *priv) } +static int +null_hostlist(hostlist_callback callback, void *arg, void *priv) +{ + VALIDATE(priv); + printf("[Null] HOSTLIST operation\n"); + + return 1; +} + + static int null_init(backend_context_t *c, config_object_t *config) { @@ -164,7 +174,8 @@ static fence_callbacks_t null_callbacks = { .on = null_on, .reboot = null_reboot, .status = null_status, - .devstatus = null_devstatus + .devstatus = null_devstatus, + .hostlist = null_hostlist }; static backend_plugin_t null_plugin = {