Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4623618
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
29 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/server/cpg-virt.c b/server/cpg-virt.c
index c3602011..80ce57b2 100644
--- a/server/cpg-virt.c
+++ b/server/cpg-virt.c
@@ -1,606 +1,633 @@
/*
Copyright Red Hat, Inc. 2017
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: Ryan McCabe <rmccabe@redhat.com>
*/
#include <config.h>
#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 <syslog.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#include <corosync/cpg.h>
#include <debug.h>
#include "virt.h"
#include "xvm.h"
#include "cpg.h"
#define NAME "cpg"
#define VERSION "0.1"
#define MAGIC 0x38e93fc2
-pthread_mutex_t vm_state_lock = PTHREAD_MUTEX_INITIALIZER;
-
struct cpg_info {
int magic;
+ config_object_t *config;
int vp_count;
virConnectPtr *vp;
};
#define VALIDATE(arg) \
do {\
if (!arg || ((struct cpg_info *) arg)->magic != MAGIC) { \
errno = EINVAL;\
return -1; \
} \
} while(0)
static struct cpg_info *cpg_virt_handle = NULL;
static int use_uuid = 0;
pthread_mutex_t local_vm_list_lock = PTHREAD_MUTEX_INITIALIZER;
static virt_list_t *local_vm_list = NULL;
pthread_mutex_t remote_vm_list_lock = PTHREAD_MUTEX_INITIALIZER;
static virt_list_t *remote_vm_list = NULL;
+static void cpg_virt_init_libvirt(struct cpg_info *info);
+
static int
virt_list_update(struct cpg_info *info, virt_list_t **vl, int my_id)
{
virt_list_t *list = NULL;
if (*vl)
vl_free(*vl);
+
list = vl_get(info->vp, info->vp_count, my_id);
- *vl = list;
+ if (!list && (errno == EPIPE || errno == EINVAL)) {
+ do {
+ cpg_virt_init_libvirt(info);
+ } while (info->vp_count == 0);
+ list = vl_get(info->vp, info->vp_count, my_id);
+ }
+ *vl = list;
if (!list)
return -1;
+
return 0;
}
static void
store_domains(virt_list_t *vl)
{
int i;
if (!vl)
return;
for (i = 0 ; i < vl->vm_count ; i++) {
int ret;
if (!strcmp(DOMAIN0NAME, vl->vm_states[i].v_name))
continue;
ret = cpg_send_vm_state(&vl->vm_states[i]);
if (ret < 0) {
printf("Error storing VM state for %s|%s\n",
vl->vm_states[i].v_name, vl->vm_states[i].v_uuid);
}
}
}
static void
update_local_vms(struct cpg_info *info)
{
uint32_t my_id = 0;
if (!info)
return;
cpg_get_ids(&my_id, NULL);
virt_list_update(info, &local_vm_list, my_id);
store_domains(local_vm_list);
}
static int
do_off(struct cpg_info *info, const char *vm_name)
{
dbg_printf(5, "%s %s\n", __FUNCTION__, vm_name);
return vm_off(info->vp, info->vp_count, vm_name);
}
static int
do_on(struct cpg_info *info, const char *vm_name)
{
dbg_printf(5, "%s %s\n", __FUNCTION__, vm_name);
return vm_on(info->vp, info->vp_count, vm_name);
}
static int
do_reboot(struct cpg_info *info, const char *vm_name)
{
dbg_printf(5, "%s %s\n", __FUNCTION__, vm_name);
return vm_reboot(info->vp, info->vp_count, vm_name);
}
static void
cpg_join_cb(const struct cpg_address *join, size_t joinlen) {
struct cpg_info *info = cpg_virt_handle;
pthread_mutex_lock(&local_vm_list_lock);
update_local_vms(info);
pthread_mutex_unlock(&local_vm_list_lock);
}
static void
cpg_leave_cb(const struct cpg_address *left, size_t leftlen) {
struct cpg_info *info = cpg_virt_handle;
int i;
pthread_mutex_lock(&remote_vm_list_lock);
for (i = 0 ; i < leftlen ; i++) {
dbg_printf(2, "Removing VMs owned by nodeid %u\n", left[i].nodeid);
vl_remove_by_owner(&remote_vm_list, left[i].nodeid);
}
pthread_mutex_unlock(&remote_vm_list_lock);
pthread_mutex_lock(&local_vm_list_lock);
update_local_vms(info);
pthread_mutex_unlock(&local_vm_list_lock);
}
static void
store_cb(void *data, size_t len, uint32_t nodeid, uint32_t seqno)
{
uint32_t my_id;
virt_state_t *vs = (virt_state_t *) data;
struct cpg_info *info = cpg_virt_handle;
cpg_get_ids(&my_id, NULL);
if (nodeid == my_id)
return;
pthread_mutex_lock(&local_vm_list_lock);
if (!local_vm_list)
update_local_vms(info);
pthread_mutex_unlock(&local_vm_list_lock);
pthread_mutex_lock(&remote_vm_list_lock);
vl_update(&remote_vm_list, vs);
pthread_mutex_unlock(&remote_vm_list_lock);
}
/*
** This function must a send reply from at least one node, otherwise
** the requesting fence_virtd will block forever in wait_cpt_reply.
*/
static void
do_real_work(void *data, size_t len, uint32_t nodeid, uint32_t seqno)
{
struct cpg_info *info = cpg_virt_handle;
struct cpg_fence_req *req = data;
struct cpg_fence_req reply;
int reply_code = -1;
virt_state_t *vs = NULL;
int cur_state;
uint32_t cur_owner = 0;
int local = 0;
uint32_t my_id, high_id;
dbg_printf(2, "Request %d for VM %s\n", req->request, req->vm_name);
if (cpg_get_ids(&my_id, &high_id) == -1) {
syslog(LOG_WARNING, "Unable to get CPG IDs");
printf("Should never happen: Can't get CPG node ids - can't proceed\n");
return;
}
memcpy(&reply, req, sizeof(reply));
pthread_mutex_lock(&local_vm_list_lock);
update_local_vms(info);
if (strlen(req->vm_name)) {
if (use_uuid)
vs = vl_find_uuid(local_vm_list, req->vm_name);
else
vs = vl_find_name(local_vm_list, req->vm_name);
if (vs) {
local = 1;
cur_owner = vs->v_state.s_owner;
cur_state = vs->v_state.s_state;
dbg_printf(2, "Found VM %s locally state %d\n",
req->vm_name, cur_state);
}
}
pthread_mutex_unlock(&local_vm_list_lock);
if (vs == NULL) {
pthread_mutex_lock(&remote_vm_list_lock);
if (strlen(req->vm_name)) {
if (use_uuid)
vs = vl_find_uuid(remote_vm_list, req->vm_name);
else
vs = vl_find_name(remote_vm_list, req->vm_name);
if (vs) {
cur_owner = vs->v_state.s_owner;
cur_state = vs->v_state.s_state;
dbg_printf(2, "Found VM %s remotely on %u state %d\n",
req->vm_name, cur_owner, cur_state);
}
}
pthread_mutex_unlock(&remote_vm_list_lock);
}
if (!vs) {
/*
** We know about all domains on all nodes in the CPG group.
** If we didn't find it, and we're high ID, act on the request.
** We can safely assume the VM is OFF because it wasn't found
** on any current members of the CPG group.
*/
if (my_id == high_id) {
if (req->request == FENCE_STATUS)
reply_code = RESP_OFF;
else if (req->request == FENCE_OFF || req->request == FENCE_REBOOT)
reply_code = RESP_SUCCESS;
else
reply_code = 1;
dbg_printf(2, "Acting on request %d for unknown domain %s -> %d\n",
req->request, req->vm_name, reply_code);
goto out;
}
dbg_printf(2, "Not acting on request %d for unknown domain %s\n",
req->request, req->vm_name);
return;
}
if (local) {
if (req->request == FENCE_STATUS) {
/* We already have the status */
if (cur_state == VIR_DOMAIN_SHUTOFF)
reply_code = RESP_OFF;
else
reply_code = RESP_SUCCESS;
} else if (req->request == FENCE_OFF) {
reply_code = do_off(info, req->vm_name);
} else if (req->request == FENCE_ON) {
reply_code = do_on(info, req->vm_name);
} else if (req->request == FENCE_REBOOT) {
reply_code = do_reboot(info, req->vm_name);
} else {
dbg_printf(2, "Not explicitly handling request type %d for %s\n",
req->request, req->vm_name);
reply_code = 0;
}
goto out;
}
/*
** This is a request for a non-local domain that exists on a
** current CPG group member, so that member will see the request
** and act on it. We don't need to do anything.
*/
dbg_printf(2, "Nothing to do for non-local domain %s seq %d owner %u\n",
req->vm_name, seqno, cur_owner);
return;
out:
dbg_printf(2, "[%s] sending reply code seq %d -> %d\n",
req->vm_name, seqno, reply_code);
reply.response = reply_code;
if (cpg_send_reply(&reply, sizeof(reply), nodeid, seqno) < 0) {
dbg_printf(2, "cpg_send_reply failed for %s [%d %d]: %s\n",
req->vm_name, nodeid, seqno, strerror(errno));
}
}
static int
do_request(const char *vm_name, int request, uint32_t seqno)
{
struct cpg_fence_req freq, *frp;
size_t retlen;
uint32_t seq;
int ret;
memset(&freq, 0, sizeof(freq));
if (!vm_name) {
dbg_printf(1, "No VM name\n");
return 1;
}
if (strlen(vm_name) >= sizeof(freq.vm_name)) {
dbg_printf(1, "VM name %s too long\n", vm_name);
return 1;
}
strcpy(freq.vm_name, vm_name);
freq.request = request;
freq.seqno = seqno;
if (cpg_send_req(&freq, sizeof(freq), &seq) != 0) {
dbg_printf(1, "Failed to send request %d for VM %s\n",
freq.request, vm_name);
return 1;
}
dbg_printf(2, "Sent request %d for VM %s got seqno %d\n",
request, vm_name, seq);
if (cpg_wait_reply((void *) &frp, &retlen, seq) != 0) {
dbg_printf(1, "Failed to receive reply seq %d for %s\n", seq, vm_name);
return 1;
}
dbg_printf(2, "Received reply [%d] seq %d for %s\n",
frp->response, seq, vm_name);
ret = frp->response;
free(frp);
return ret;
}
static int
cpg_virt_null(const char *vm_name, void *priv)
{
VALIDATE(priv);
printf("[cpg-virt] Null operation on %s\n", vm_name);
return 1;
}
static int
cpg_virt_off(const char *vm_name, const char *src, uint32_t seqno, void *priv)
{
VALIDATE(priv);
printf("[cpg-virt] OFF operation on %s seq %d\n", vm_name, seqno);
return do_request(vm_name, FENCE_OFF, seqno);
}
static int
cpg_virt_on(const char *vm_name, const char *src, uint32_t seqno, void *priv)
{
VALIDATE(priv);
printf("[cpg-virt] ON operation on %s seq %d\n", vm_name, seqno);
return do_request(vm_name, FENCE_ON, seqno);
}
static int
cpg_virt_devstatus(void *priv)
{
printf("[cpg-virt] Device status\n");
VALIDATE(priv);
return 0;
}
static int
cpg_virt_status(const char *vm_name, void *priv)
{
VALIDATE(priv);
printf("[cpg-virt] STATUS operation on %s\n", vm_name);
return do_request(vm_name, FENCE_STATUS, 0);
}
static int
cpg_virt_reboot(const char *vm_name, const char *src,
uint32_t seqno, void *priv)
{
VALIDATE(priv);
printf("[cpg-virt] REBOOT operation on %s seq %d\n", vm_name, seqno);
return do_request(vm_name, FENCE_REBOOT, 0);
}
static int
cpg_virt_hostlist(hostlist_callback callback, void *arg, void *priv)
{
VALIDATE(priv);
printf("[cpg-virt] HOSTLIST operation\n");
return 1;
}
-static int
-cpg_virt_init(backend_context_t *c, config_object_t *config)
-{
- char value[1024];
- struct cpg_info *info = NULL;
+static void
+cpg_virt_init_libvirt(struct cpg_info *info) {
+ config_object_t *config = info->config;
int i = 0;
- int ret;
- ret = cpg_start(PACKAGE_NAME,
- do_real_work, store_cb, cpg_join_cb, cpg_leave_cb);
- if (ret < 0)
- return -1;
-
- info = calloc(1, sizeof(*info));
- if (!info)
- return -1;
- info->magic = MAGIC;
-
-#ifdef _MODULE
- if (sc_get(config, "fence_virtd/@debug", value, sizeof(value))==0)
- dset(atoi(value));
-#endif
+ if (info->vp) {
+ dbg_printf(2, "Lost libvirtd connection. Reinitializing.\n");
+ for (i = 0 ; i < info->vp_count ; i++)
+ virConnectClose(info->vp[i]);
+ free(info->vp);
+ info->vp = NULL;
+ }
+ info->vp_count = 0;
do {
virConnectPtr vp;
virConnectPtr *vpl = NULL;
char conf_attr[256];
+ char value[1024];
char *uri;
if (i != 0) {
snprintf(conf_attr, sizeof(conf_attr),
"backends/cpg/@uri%d", i);
} else
snprintf(conf_attr, sizeof(conf_attr), "backends/cpg/@uri");
++i;
if (sc_get(config, conf_attr, value, sizeof(value)) != 0)
break;
uri = value;
vp = virConnectOpen(uri);
if (!vp) {
dbg_printf(1, "[cpg-virt:INIT] Failed to connect to URI: %s\n", uri);
continue;
}
vpl = realloc(info->vp, sizeof(*info->vp) * (info->vp_count + 1));
if (!vpl) {
dbg_printf(1, "[cpg-virt:INIT] Out of memory allocating URI: %s\n",
uri);
virConnectClose(vp);
continue;
}
info->vp = vpl;
info->vp[info->vp_count++] = vp;
if (i > 1)
dbg_printf(1, "[cpg-virt:INIT] Added URI%d %s\n", i - 1, uri);
else
dbg_printf(1, "[cpg_virt:INIT] Added URI %s\n", uri);
} while (1);
+}
+
+static int
+cpg_virt_init(backend_context_t *c, config_object_t *config)
+{
+ char value[1024];
+ struct cpg_info *info = NULL;
+ int ret;
+
+ ret = cpg_start(PACKAGE_NAME,
+ do_real_work, store_cb, cpg_join_cb, cpg_leave_cb);
+ if (ret < 0)
+ return -1;
+
+ info = calloc(1, sizeof(*info));
+ if (!info)
+ return -1;
+ info->magic = MAGIC;
+ info->config = config;
+
+#ifdef _MODULE
+ if (sc_get(config, "fence_virtd/@debug", value, sizeof(value)) == 0)
+ dset(atoi(value));
+#endif
+
+ cpg_virt_init_libvirt(info);
/* Naming scheme is no longer a top-level config option.
* However, we retain it here for configuration compatibility with
* versions 0.1.3 and previous.
*/
if (sc_get(config, "fence_virtd/@name_mode",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for name_mode\n", value);
if (!strcasecmp(value, "uuid")) {
use_uuid = 1;
} else if (!strcasecmp(value, "name")) {
use_uuid = 0;
} else {
dbg_printf(1, "Unsupported name_mode: %s\n", value);
}
}
if (sc_get(config, "backends/cpg/@name_mode",
- value, sizeof(value)-1) == 0) {
-
+ value, sizeof(value)-1) == 0)
+ {
dbg_printf(1, "Got %s for name_mode\n", value);
if (!strcasecmp(value, "uuid")) {
use_uuid = 1;
} else if (!strcasecmp(value, "name")) {
use_uuid = 0;
} else {
dbg_printf(1, "Unsupported name_mode: %s\n", value);
}
}
pthread_mutex_lock(&local_vm_list_lock);
update_local_vms(info);
pthread_mutex_unlock(&local_vm_list_lock);
- *c = (void *)info;
+ *c = (void *) info;
cpg_virt_handle = info;
return 0;
}
static int
cpg_virt_shutdown(backend_context_t c)
{
struct cpg_info *info = (struct cpg_info *)c;
int i = 0;
int ret = 0;
VALIDATE(info);
info->magic = 0;
for (i = 0 ; i < info->vp_count ; i++) {
if (virConnectClose(info->vp[i]) < 0)
ret = -errno;
}
free(info->vp);
free(info);
cpg_stop();
return ret;
}
static fence_callbacks_t cpg_callbacks = {
.null = cpg_virt_null,
.off = cpg_virt_off,
.on = cpg_virt_on,
.reboot = cpg_virt_reboot,
.status = cpg_virt_status,
.devstatus = cpg_virt_devstatus,
.hostlist = cpg_virt_hostlist
};
static backend_plugin_t cpg_virt_plugin = {
.name = NAME,
.version = VERSION,
.callbacks = &cpg_callbacks,
.init = cpg_virt_init,
.cleanup = cpg_virt_shutdown,
};
#ifdef _MODULE
double
BACKEND_VER_SYM(void)
{
return PLUGIN_VERSION_BACKEND;
}
const backend_plugin_t *
BACKEND_INFO_SYM(void)
{
return &cpg_virt_plugin;
}
#else
static void __attribute__((constructor))
cpg_register_plugin(void)
{
plugin_reg_backend(&cpg_virt_plugin);
}
#endif
diff --git a/server/virt.c b/server/virt.c
index 9c90a033..97107910 100644
--- a/server/virt.c
+++ b/server/virt.c
@@ -1,615 +1,625 @@
/*
Copyright Red Hat, Inc. 2006-2017
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.
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <libvirt/libvirt.h>
#include <string.h>
#include <malloc.h>
#include <stdint.h>
#include <errno.h>
#include <syslog.h>
#include "debug.h"
#include "uuid-test.h"
#include "virt.h"
static int
_compare_virt(const void *_left, const void *_right)
{
virt_state_t *left = (virt_state_t *)_left,
*right = (virt_state_t *)_right;
return strcasecmp(left->v_name, right->v_name);
}
static void
_free_dom_list(virDomainPtr *dom_list, int len) {
int x;
if (!dom_list || len <= 0)
return;
for (x = 0 ; x < len; x++)
virDomainFree(dom_list[x]);
free(dom_list);
}
virt_list_t *vl_get(virConnectPtr *vp, int vp_count, int my_id)
{
virt_list_t *vl = NULL;
int d_count = 0;
int i;
errno = EINVAL;
if (!vp || vp_count < 1)
return NULL;
for (i = 0 ; i < vp_count ; i++) {
int x;
virDomainPtr *dom_list;
virt_list_t *new_vl;
int ret = virConnectListAllDomains(vp[i], &dom_list, 0);
- if (ret <= 0)
+ if (ret == 0)
continue;
+ if (ret < 0) {
+ int saved_errno = errno;
+ dbg_printf(2, "Error: virConnectListAllDomains: %d %d\n",
+ ret, saved_errno);
+ if (vl)
+ free(vl);
+ errno = saved_errno;
+ return NULL;
+ }
+
d_count += ret;
new_vl = realloc(vl, sizeof(uint32_t) + sizeof(virt_state_t) * d_count);
if (!new_vl) {
_free_dom_list(dom_list, ret);
free(vl);
return NULL;
}
vl = new_vl;
vl->vm_count = d_count;
/* Ok, we have the domain IDs - let's get their names and states */
for (x = 0; x < ret; x++) {
char *d_name;
virDomainInfo d_info;
char d_uuid[MAX_DOMAINNAME_LENGTH];
virDomainPtr dom = dom_list[x];
if (!(d_name = (char *)virDomainGetName(dom))) {
_free_dom_list(dom_list, ret);
free(vl);
return NULL;
}
if (virDomainGetUUIDString(dom, d_uuid) != 0) {
_free_dom_list(dom_list, ret);
free(vl);
return NULL;
}
if (virDomainGetInfo(dom, &d_info) < 0) {
_free_dom_list(dom_list, ret);
free(vl);
return NULL;
}
/* Store the name & state */
strncpy(vl->vm_states[x].v_name, d_name, MAX_DOMAINNAME_LENGTH);
strncpy(vl->vm_states[x].v_uuid, d_uuid, MAX_DOMAINNAME_LENGTH);
vl->vm_states[x].v_state.s_state = d_info.state;
vl->vm_states[x].v_state.s_owner = my_id;
}
_free_dom_list(dom_list, ret);
}
/* We have all the locally running domains & states now */
/* Sort */
qsort(&vl->vm_states[0], vl->vm_count, sizeof(vl->vm_states[0]),
_compare_virt);
return vl;
}
int
vl_add(virt_list_t **vl, virt_state_t *vm) {
virt_list_t *new_vl;
size_t oldlen;
size_t newlen;
if (!vl)
return -1;
if (!*vl) {
*vl = malloc(sizeof(uint32_t) + sizeof(virt_state_t));
if (!*vl)
return -1;
(*vl)->vm_count = 1;
memcpy(&(*vl)->vm_states[0], vm, sizeof(virt_state_t));
return 0;
}
oldlen = sizeof(uint32_t) + sizeof(virt_state_t) * (*vl)->vm_count;
newlen = oldlen + sizeof(virt_state_t);
new_vl = malloc(newlen);
if (!new_vl)
return -1;
memcpy(new_vl, *vl, oldlen);
memcpy(&new_vl->vm_states[(*vl)->vm_count], vm, sizeof(virt_state_t));
new_vl->vm_count++;
free(*vl);
*vl = new_vl;
return 0;
}
int vl_remove_by_owner(virt_list_t **vl, uint32_t owner) {
int i;
int removed = 0;
virt_list_t *new_vl;
if (!vl || !*vl)
return 0;
for (i = 0 ; i < (*vl)->vm_count ; i++) {
if ((*vl)->vm_states[i].v_state.s_owner == owner) {
dbg_printf(2, "Removing %s\n", (*vl)->vm_states[i].v_name);
memset(&(*vl)->vm_states[i].v_state, 0,
sizeof((*vl)->vm_states[i].v_state));
(*vl)->vm_states[i].v_name[0] = 0xff;
(*vl)->vm_states[i].v_uuid[0] = 0xff;
removed++;
}
}
if (!removed)
return 0;
qsort(&(*vl)->vm_states[0], (*vl)->vm_count, sizeof((*vl)->vm_states[0]),
_compare_virt);
(*vl)->vm_count -= removed;
new_vl = realloc(*vl, sizeof(uint32_t) + (sizeof(virt_state_t) * ((*vl)->vm_count)));
if (new_vl)
*vl = new_vl;
return removed;
}
int
vl_update(virt_list_t **vl, virt_state_t *vm) {
virt_state_t *v = NULL;
if (!vl)
return -1;
if (!*vl)
return vl_add(vl, vm);
if (strlen(vm->v_uuid) > 0)
v = vl_find_uuid(*vl, vm->v_uuid);
if (v == NULL && strlen(vm->v_name) > 0)
v = vl_find_name(*vl, vm->v_name);
if (v == NULL) {
dbg_printf(2, "Adding new entry for VM %s\n", vm->v_name);
vl_add(vl, vm);
} else {
dbg_printf(2, "Updating entry for VM %s\n", vm->v_name);
memcpy(&v->v_state, &vm->v_state, sizeof(v->v_state));
}
return 0;
}
void
vl_print(virt_list_t *vl)
{
int x;
printf("%-24.24s %-36.36s %-5.5s %-5.5s\n", "Domain", "UUID",
"Owner", "State");
printf("%-24.24s %-36.36s %-5.5s %-5.5s\n", "------", "----",
"-----", "-----");
if (!vl || !vl->vm_count)
return;
for (x = 0; x < vl->vm_count; x++) {
printf("%-24.24s %-36.36s %-5.5d %-5.5d\n",
vl->vm_states[x].v_name,
vl->vm_states[x].v_uuid,
vl->vm_states[x].v_state.s_owner,
vl->vm_states[x].v_state.s_state);
}
}
virt_state_t *
vl_find_name(virt_list_t *vl, const char *name)
{
int x;
if (!vl || !name || !vl->vm_count)
return NULL;
for (x = 0; x < vl->vm_count; x++) {
if (!strcasecmp(vl->vm_states[x].v_name, name))
return &vl->vm_states[x];
}
return NULL;
}
virt_state_t *
vl_find_uuid(virt_list_t *vl, const char *uuid)
{
int x;
if (!vl || !uuid || !vl->vm_count)
return NULL;
for (x = 0; x < vl->vm_count; x++) {
if (!strcasecmp(vl->vm_states[x].v_uuid, uuid))
return &vl->vm_states[x];
}
return NULL;
}
void
vl_free(virt_list_t *old)
{
free(old);
}
static inline int
wait_domain(const char *vm_name, virConnectPtr vp, int timeout)
{
int tries = 0;
int response = 1;
int ret;
virDomainPtr vdp;
virDomainInfo vdi;
int uuid_check;
uuid_check = is_uuid(vm_name);
if (uuid_check) {
vdp = virDomainLookupByUUIDString(vp, (const char *)vm_name);
} else {
vdp = virDomainLookupByName(vp, vm_name);
}
if (!vdp)
return 0;
/* Check domain liveliness. If the domain is still here,
we return failure, and the client must then retry */
/* XXX On the xen 3.0.4 API, we will be able to guarantee
synchronous virDomainDestroy, so this check will not
be necessary */
do {
if (++tries > timeout)
break;
sleep(1);
if (uuid_check) {
vdp = virDomainLookupByUUIDString(vp, (const char *)vm_name);
} else {
vdp = virDomainLookupByName(vp, vm_name);
}
if (!vdp) {
dbg_printf(2, "Domain no longer exists\n");
response = 0;
break;
}
memset(&vdi, 0, sizeof(vdi));
ret = virDomainGetInfo(vdp, &vdi);
virDomainFree(vdp);
if (ret < 0)
continue;
if (vdi.state == VIR_DOMAIN_SHUTOFF) {
dbg_printf(2, "Domain has been shut off\n");
response = 0;
break;
}
dbg_printf(4, "Domain still exists (state %d) after %d seconds\n",
vdi.state, tries);
} while (1);
return response;
}
int
vm_off(virConnectPtr *vp, int vp_count, const char *vm_name)
{
virDomainPtr vdp = NULL;
virDomainInfo vdi;
virDomainPtr (*virt_lookup_fn)(virConnectPtr, const char *);
int ret = -1;
int i;
if (is_uuid(vm_name))
virt_lookup_fn = virDomainLookupByUUIDString;
else
virt_lookup_fn = virDomainLookupByName;
for (i = 0 ; i < vp_count ; i++) {
vdp = virt_lookup_fn(vp[i], vm_name);
if (vdp)
break;
}
if (!vdp) {
dbg_printf(2, "[virt:OFF] Domain %s does not exist\n", vm_name);
return 1;
}
if (virDomainGetInfo(vdp, &vdi) == 0 && vdi.state == VIR_DOMAIN_SHUTOFF)
{
dbg_printf(2, "[virt:OFF] Nothing to do - "
"domain %s is already off\n",
vm_name);
virDomainFree(vdp);
return 0;
}
syslog(LOG_NOTICE, "Destroying domain %s\n", vm_name);
dbg_printf(2, "[virt:OFF] Calling virDomainDestroy for %s\n", vm_name);
ret = virDomainDestroy(vdp);
virDomainFree(vdp);
if (ret < 0) {
syslog(LOG_NOTICE,
"Failed to destroy domain %s: %d\n", vm_name, ret);
dbg_printf(2, "[virt:OFF] Failed to destroy domain: %s %d\n",
vm_name, ret);
return 1;
}
if (ret) {
syslog(LOG_NOTICE, "Domain %s still exists; fencing failed\n",
vm_name);
dbg_printf(2,
"[virt:OFF] Domain %s still exists; fencing failed\n",
vm_name);
return 1;
}
dbg_printf(2, "[virt:OFF] Success for %s\n", vm_name);
return 0;
}
int
vm_on(virConnectPtr *vp, int vp_count, const char *vm_name)
{
virDomainPtr vdp = NULL;
virDomainInfo vdi;
virDomainPtr (*virt_lookup_fn)(virConnectPtr, const char *);
int ret = -1;
int i;
if (is_uuid(vm_name))
virt_lookup_fn = virDomainLookupByUUIDString;
else
virt_lookup_fn = virDomainLookupByName;
for (i = 0 ; i < vp_count ; i++) {
vdp = virt_lookup_fn(vp[i], vm_name);
if (vdp)
break;
}
if (!vdp) {
dbg_printf(2, "[virt:ON] Domain %s does not exist\n", vm_name);
return 1;
}
if (virDomainGetInfo(vdp, &vdi) == 0 && vdi.state != VIR_DOMAIN_SHUTOFF) {
dbg_printf(2, "Nothing to do - domain %s is already running\n",
vm_name);
virDomainFree(vdp);
return 0;
}
syslog(LOG_NOTICE, "Starting domain %s\n", vm_name);
dbg_printf(2, "[virt:ON] Calling virDomainCreate for %s\n", vm_name);
ret = virDomainCreate(vdp);
virDomainFree(vdp);
if (ret < 0) {
syslog(LOG_NOTICE, "Failed to start domain %s: %d\n", vm_name, ret);
dbg_printf(2, "[virt:ON] virDomainCreate() failed for %s: %d\n",
vm_name, ret);
return 1;
}
if (ret) {
syslog(LOG_NOTICE, "Domain %s did not start\n", vm_name);
dbg_printf(2, "[virt:ON] Domain %s did not start\n", vm_name);
return 1;
}
syslog(LOG_NOTICE, "Domain %s started\n", vm_name);
dbg_printf(2, "[virt:ON] Success for %s\n", vm_name);
return 0;
}
int
vm_status(virConnectPtr *vp, int vp_count, const char *vm_name)
{
virDomainPtr vdp = NULL;
virDomainInfo vdi;
int ret = 0;
int i;
virDomainPtr (*virt_lookup_fn)(virConnectPtr, const char *);
if (is_uuid(vm_name))
virt_lookup_fn = virDomainLookupByUUIDString;
else
virt_lookup_fn = virDomainLookupByName;
for (i = 0 ; i < vp_count ; i++) {
vdp = virt_lookup_fn(vp[i], vm_name);
if (vdp)
break;
}
if (!vdp) {
dbg_printf(2, "[virt:STATUS] Unknown VM %s - return OFF\n", vm_name);
return RESP_OFF;
}
if (virDomainGetInfo(vdp, &vdi) == 0 && vdi.state == VIR_DOMAIN_SHUTOFF) {
dbg_printf(2, "[virt:STATUS] VM %s is OFF\n", vm_name);
ret = RESP_OFF;
}
if (vdp)
virDomainFree(vdp);
return ret;
}
int
vm_reboot(virConnectPtr *vp, int vp_count, const char *vm_name)
{
virDomainPtr vdp = NULL, nvdp;
virDomainInfo vdi;
char *domain_desc;
virConnectPtr vcp = NULL;
virDomainPtr (*virt_lookup_fn)(virConnectPtr, const char *);
int ret;
int i;
if (is_uuid(vm_name))
virt_lookup_fn = virDomainLookupByUUIDString;
else
virt_lookup_fn = virDomainLookupByName;
for (i = 0 ; i < vp_count ; i++) {
vdp = virt_lookup_fn(vp[i], vm_name);
if (vdp) {
vcp = vp[i];
break;
}
}
if (!vdp || !vcp) {
dbg_printf(2,
"[virt:REBOOT] Nothing to do - domain %s does not exist\n",
vm_name);
return 1;
}
if (virDomainGetInfo(vdp, &vdi) == 0 && vdi.state == VIR_DOMAIN_SHUTOFF) {
dbg_printf(2, "[virt:REBOOT] Nothing to do - domain %s is off\n",
vm_name);
virDomainFree(vdp);
return 0;
}
syslog(LOG_NOTICE, "Rebooting domain %s\n", vm_name);
dbg_printf(5, "[virt:REBOOT] Rebooting domain %s...\n", vm_name);
domain_desc = virDomainGetXMLDesc(vdp, 0);
if (!domain_desc) {
dbg_printf(5, "[virt:REBOOT] Failed getting domain description "
"from libvirt for %s...\n", vm_name);
}
dbg_printf(2, "[virt:REBOOT] Calling virDomainDestroy(%p) for %s\n",
vdp, vm_name);
ret = virDomainDestroy(vdp);
if (ret < 0) {
dbg_printf(2,
"[virt:REBOOT] virDomainDestroy() failed for %s: %d/%d\n",
vm_name, ret, errno);
if (domain_desc)
free(domain_desc);
virDomainFree(vdp);
return 1;
}
ret = wait_domain(vm_name, vcp, 15);
if (ret) {
syslog(LOG_NOTICE, "Domain %s still exists; fencing failed\n", vm_name);
dbg_printf(2,
"[virt:REBOOT] Domain %s still exists; fencing failed\n",
vm_name);
if (domain_desc)
free(domain_desc);
virDomainFree(vdp);
return 1;
}
if (!domain_desc)
return 0;
/* 'on' is not a failure */
ret = 0;
dbg_printf(3, "[[ XML Domain Info ]]\n");
dbg_printf(3, "%s\n[[ XML END ]]\n", domain_desc);
dbg_printf(2, "[virt:REBOOT] Calling virDomainCreateLinux() for %s\n",
vm_name);
nvdp = virDomainCreateLinux(vcp, domain_desc, 0);
if (nvdp == NULL) {
/* More recent versions of libvirt or perhaps the
* KVM back-end do not let you create a domain from
* XML if there is already a defined domain description
* with the same name that it knows about. You must
* then call virDomainCreate() */
dbg_printf(2,
"[virt:REBOOT] virDomainCreateLinux() failed for %s; "
"Trying virDomainCreate()\n",
vm_name);
if (virDomainCreate(vdp) < 0) {
syslog(LOG_NOTICE, "Could not restart %s\n", vm_name);
dbg_printf(1, "[virt:REBOOT] Failed to recreate guest %s!\n",
vm_name);
}
}
free(domain_desc);
virDomainFree(vdp);
return ret;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Tue, Jul 8, 4:29 PM (1 d, 44 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1991910
Default Alt Text
(29 KB)
Attached To
Mode
rF Fence Agents
Attached
Detach File
Event Timeline
Log In to Comment