fence-virt/server/virt.c
Ryan McCabe 7f6798916a fence_virtd: Remove checkpoint, replace it with a CPG only plugin
Remove the checkpoint backend plugin, as it used CMAN and openais
checkpoints. Given nobody is using CMAN or openais anymore, the plugin
was useless for clusters running the current stack.

Signed-off-by: Ryan McCabe <rmccabe@redhat.com>
2017-05-27 21:23:03 -04:00

616 lines
13 KiB
C

/*
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)
continue;
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;
}