From 2520b61d1401344d632dc40b0972efa7786d1d9e Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Apr 10 2018 05:10:21 +0000 Subject: import fence-virt-0.3.2-13.el7 --- diff --git a/SOURCES/bz1384181-make_the_libvirt_backend_survive_libvirtd.patch b/SOURCES/bz1384181-make_the_libvirt_backend_survive_libvirtd.patch new file mode 100644 index 0000000..522bf0d --- /dev/null +++ b/SOURCES/bz1384181-make_the_libvirt_backend_survive_libvirtd.patch @@ -0,0 +1,1147 @@ +diff -ur a/server/checkpoint.c b/server/checkpoint.c +--- a/server/checkpoint.c 2014-06-23 15:56:09.000000000 -0400 ++++ b/server/checkpoint.c 2017-08-09 13:30:40.708689303 -0400 +@@ -79,7 +79,7 @@ + { + virt_list_t *list = NULL; + +- list = vl_get(vp, my_id); ++ list = vl_get(vp, 1, my_id); + if (!list) + return -1; + +diff -ur a/server/libvirt.c b/server/libvirt.c +--- a/server/libvirt.c 2014-06-23 15:56:09.000000000 -0400 ++++ b/server/libvirt.c 2017-08-09 13:30:40.709689288 -0400 +@@ -1,5 +1,5 @@ + /* +- Copyright Red Hat, Inc. 2006 ++ 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 +@@ -61,13 +61,15 @@ + + + #define NAME "libvirt" +-#define VERSION "0.1" ++#define VERSION "0.3" + + #define MAGIC 0x1e19317a + + struct libvirt_info { + int magic; +- virConnectPtr vp; ++ config_object_t *config; ++ int vp_count; ++ virConnectPtr *vp; + }; + + #define VALIDATE(arg) \ +@@ -79,179 +81,128 @@ + } while(0) + + +-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); ++static void ++libvirt_init_libvirt_conf(struct libvirt_info *info) { ++ config_object_t *config = info->config; ++ int i = 0; ++ ++ 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; + } +- if (!vdp) +- return 0; ++ info->vp_count = 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; ++ virConnectPtr vp; ++ virConnectPtr *vpl = NULL; ++ char conf_attr[256]; ++ char value[1024]; ++ char *uri; ++ ++ if (i != 0) { ++ snprintf(conf_attr, sizeof(conf_attr), ++ "backends/libvirt/@uri%d", i); ++ } else ++ snprintf(conf_attr, sizeof(conf_attr), "backends/libvirt/@uri"); ++ ++i; + +- 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; ++ if (sc_get(config, conf_attr, value, sizeof(value)) != 0) + break; +- } + +- memset(&vdi, 0, sizeof(vdi)); +- ret = virDomainGetInfo(vdp, &vdi); +- virDomainFree(vdp); +- if (ret < 0) ++ uri = value; ++ vp = virConnectOpen(uri); ++ if (!vp) { ++ dbg_printf(1, "[libvirt:INIT] Failed to connect to URI: %s\n", uri); + continue; ++ } + +- if (vdi.state == VIR_DOMAIN_SHUTOFF) { +- dbg_printf(2, "Domain has been shut off\n"); +- response = 0; +- break; ++ vpl = realloc(info->vp, sizeof(*info->vp) * (info->vp_count + 1)); ++ if (!vpl) { ++ dbg_printf(1, "[libvirt:INIT] Out of memory allocating URI: %s\n", ++ uri); ++ virConnectClose(vp); ++ continue; + } +- +- dbg_printf(4, "Domain still exists (state %d) " +- "after %d seconds\n", +- vdi.state, tries); ++ ++ info->vp = vpl; ++ info->vp[info->vp_count++] = vp; ++ ++ if (i > 1) ++ dbg_printf(1, "[libvirt:INIT] Added URI%d %s\n", i - 1, uri); ++ else ++ dbg_printf(1, "[libvirt:INIT] Added URI %s\n", uri); + } while (1); ++} + +- return response; ++ ++static int ++libvirt_bad_connections(struct libvirt_info *info) { ++ int bad = 0; ++ int i; ++ ++ for (i = 0 ; i < info->vp_count ; i++) { ++ /* ++ ** Send a dummy command to trigger an error if libvirtd ++ ** died or restarted ++ */ ++ virConnectNumOfDomains(info->vp[i]); ++ if (!virConnectIsAlive(info->vp[i])) { ++ dbg_printf(1, "libvirt connection %d is dead\n", i); ++ bad++; ++ } ++ } ++ ++ if (info->vp_count < 1 || bad) ++ libvirt_init_libvirt_conf(info); ++ ++ return bad || info->vp_count < 1; + } + ++static void ++libvirt_validate_connections(struct libvirt_info *info) { ++ while (1) { ++ if (libvirt_bad_connections(info)) ++ sleep(1); ++ else ++ break; ++ } ++} + + static int + libvirt_null(const char *vm_name, void *priv) + { +- dbg_printf(5, "%s %s\n", __FUNCTION__, vm_name); ++ dbg_printf(5, "ENTER %s %s\n", __FUNCTION__, vm_name); + printf("NULL operation: returning failure\n"); + return 1; + } + + + static int +-libvirt_off(const char *vm_name, const char *src, +- uint32_t seqno, void *priv) ++libvirt_off(const char *vm_name, const char *src, uint32_t seqno, void *priv) + { + struct libvirt_info *info = (struct libvirt_info *)priv; +- virDomainPtr vdp; +- virDomainInfo vdi; +- int ret = -1; + +- dbg_printf(5, "%s %s\n", __FUNCTION__, vm_name); ++ dbg_printf(5, "ENTER %s %s %u\n", __FUNCTION__, vm_name, seqno); + VALIDATE(info); + +- if (is_uuid(vm_name)) { +- vdp = virDomainLookupByUUIDString(info->vp, +- (const char *)vm_name); +- } else { +- vdp = virDomainLookupByName(info->vp, vm_name); +- } +- +- if (!vdp) { +- dbg_printf(2, "Nothing to do - domain does not exist\n"); +- return 1; +- } +- +- if (((virDomainGetInfo(vdp, &vdi) == 0) && +- (vdi.state == VIR_DOMAIN_SHUTOFF))) { +- dbg_printf(2, "Nothing to do - domain is off\n"); +- virDomainFree(vdp); +- return 0; +- } +- +- syslog(LOG_NOTICE, "Destroying domain %s\n", vm_name); +- dbg_printf(2, "[OFF] Calling virDomainDestroy\n"); +- ret = virDomainDestroy(vdp); +- if (ret < 0) { +- syslog(LOG_NOTICE, "Failed to destroy domain: %d\n", ret); +- printf("virDomainDestroy() failed: %d\n", ret); +- return 1; +- } +- +- if (ret) { +- syslog(LOG_NOTICE, +- "Domain %s still exists; fencing failed\n", +- vm_name); +- printf("Domain %s still exists; fencing failed\n", vm_name); +- return 1; +- } +- +- return 0; ++ libvirt_validate_connections(info); ++ return vm_off(info->vp, info->vp_count, vm_name); + } + + + static int +-libvirt_on(const char *vm_name, const char *src, +- uint32_t seqno, void *priv) ++libvirt_on(const char *vm_name, const char *src, uint32_t seqno, void *priv) + { + struct libvirt_info *info = (struct libvirt_info *)priv; +- virDomainPtr vdp; +- virDomainInfo vdi; +- int ret = -1; + +- dbg_printf(5, "%s %s\n", __FUNCTION__, vm_name); ++ dbg_printf(5, "ENTER %s %s %u\n", __FUNCTION__, vm_name, seqno); + VALIDATE(info); + +- if (is_uuid(vm_name)) { +- vdp = virDomainLookupByUUIDString(info->vp, +- (const char *)vm_name); +- } else { +- vdp = virDomainLookupByName(info->vp, vm_name); +- } +- +- if (vdp && +- ((virDomainGetInfo(vdp, &vdi) == 0) && +- (vdi.state != VIR_DOMAIN_SHUTOFF))) { +- dbg_printf(2, "Nothing to do - domain is running\n"); +- +- if (vdp) +- virDomainFree(vdp); +- return 0; +- } +- +- syslog(LOG_NOTICE, "Starting domain %s\n", vm_name); +- dbg_printf(2, "[ON] Calling virDomainCreate\n"); +- ret = virDomainCreate(vdp); +- if (ret < 0) { +- syslog(LOG_NOTICE, "Failed to start domain: %d\n", ret); +- printf("virDomainCreate() failed: %d\n", ret); +- return 1; +- } +- +- if (ret) { +- syslog(LOG_NOTICE, +- "Domain %s did not start\n", +- vm_name); +- printf("Domain %s did not start\n", vm_name); +- return 1; +- } +- syslog(LOG_NOTICE, "Domain %s started\n", vm_name); +- +- return 0; ++ libvirt_validate_connections(info); ++ return vm_on(info->vp, info->vp_count, vm_name); + } + + +@@ -270,126 +221,25 @@ + libvirt_status(const char *vm_name, void *priv) + { + struct libvirt_info *info = (struct libvirt_info *)priv; +- virDomainPtr vdp; +- virDomainInfo vdi; +- int ret = 0; + +- dbg_printf(5, "%s %s\n", __FUNCTION__, vm_name); ++ dbg_printf(5, "ENTER %s %s\n", __FUNCTION__, vm_name); + VALIDATE(info); + +- if (is_uuid(vm_name)) { +- vdp = virDomainLookupByUUIDString(info->vp, +- (const char *)vm_name); +- } else { +- vdp = virDomainLookupByName(info->vp, vm_name); +- } +- +- if (!vdp || ((virDomainGetInfo(vdp, &vdi) == 0) && +- (vdi.state == VIR_DOMAIN_SHUTOFF))) { +- ret = RESP_OFF; +- } +- +- if (vdp) +- virDomainFree(vdp); +- return ret; ++ libvirt_validate_connections(info); ++ return vm_status(info->vp, info->vp_count, vm_name); + } + + + static int +-libvirt_reboot(const char *vm_name, const char *src, +- uint32_t seqno, void *priv) ++libvirt_reboot(const char *vm_name, const char *src, uint32_t seqno, void *priv) + { + struct libvirt_info *info = (struct libvirt_info *)priv; +- virDomainPtr vdp, nvdp; +- virDomainInfo vdi; +- char *domain_desc; +- int ret; + +- //uuid_unparse(vm_uuid, uu_string); +- dbg_printf(5, "%s %s\n", __FUNCTION__, vm_name); ++ dbg_printf(5, "ENTER %s %s %u\n", __FUNCTION__, vm_name, seqno); + VALIDATE(info); +- +- if (is_uuid(vm_name)) { +- vdp = virDomainLookupByUUIDString(info->vp, +- (const char *)vm_name); +- } else { +- vdp = virDomainLookupByName(info->vp, vm_name); +- } +- +- if (!vdp) { +- dbg_printf(2, "[libvirt:REBOOT] Nothing to " +- "do - domain does not exist\n"); +- return 1; +- } +- +- if (((virDomainGetInfo(vdp, &vdi) == 0) && +- (vdi.state == VIR_DOMAIN_SHUTOFF))) { +- dbg_printf(2, "[libvirt:REBOOT] Nothing to " +- "do - domain is off\n"); +- virDomainFree(vdp); +- return 0; +- } +- +- +- syslog(LOG_NOTICE, "Rebooting domain %s\n", vm_name); +- printf("Rebooting domain %s...\n", vm_name); +- domain_desc = virDomainGetXMLDesc(vdp, 0); +- +- if (!domain_desc) { +- printf("Failed getting domain description from " +- "libvirt\n"); +- } +- +- dbg_printf(2, "[REBOOT] Calling virDomainDestroy(%p)\n", vdp); +- ret = virDomainDestroy(vdp); +- if (ret < 0) { +- printf("virDomainDestroy() failed: %d/%d\n", ret, errno); +- free(domain_desc); +- virDomainFree(vdp); +- return 1; +- } +- +- ret = wait_domain(vm_name, info->vp, 15); +- +- if (ret) { +- syslog(LOG_NOTICE, "Domain %s still exists; fencing failed\n", +- vm_name); +- printf("Domain %s still exists; fencing failed\n", vm_name); +- if (domain_desc) +- free(domain_desc); +- 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, "Calling virDomainCreateLinux()...\n"); +- +- nvdp = virDomainCreateLinux(info->vp, 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, "Failed; Trying virDomainCreate()...\n"); +- if (virDomainCreate(vdp) < 0) { +- syslog(LOG_NOTICE, +- "Could not restart %s\n", +- vm_name); +- dbg_printf(1, "Failed to recreate guest" +- " %s!\n", vm_name); +- } +- } +- +- free(domain_desc); +- +- return ret; ++ libvirt_validate_connections(info); ++ return vm_reboot(info->vp, info->vp_count, vm_name); + } + + +@@ -400,22 +250,27 @@ + virt_list_t *vl; + int x; + +- dbg_printf(5, "%s\n", __FUNCTION__); ++ dbg_printf(5, "ENTER %s\n", __FUNCTION__); + VALIDATE(info); + +- vl = vl_get(info->vp, 1); ++ libvirt_validate_connections(info); ++ ++ vl = vl_get(info->vp, info->vp_count, 1); + if (!vl) +- return 1; ++ return 0; + + for (x = 0; x < vl->vm_count; x++) { +- dbg_printf(10, "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->vm_states[x].v_uuid, ++ vl->vm_states[x].v_state.s_state, arg); ++ ++ dbg_printf(10, "[libvirt:HOSTLIST] Sent %s %s %d\n", ++ vl->vm_states[x].v_name, ++ vl->vm_states[x].v_uuid, ++ vl->vm_states[x].v_state.s_state); + } + + vl_free(vl); +- + return 0; + } + +@@ -423,46 +278,33 @@ + static int + libvirt_init(backend_context_t *c, config_object_t *config) + { +- virConnectPtr vp; + char value[256]; + struct libvirt_info *info = NULL; +- char *uri = NULL; + +- info = malloc(sizeof(*info)); ++ dbg_printf(5, "ENTER [%s:%d %s]\n", __FILE__, __LINE__, __FUNCTION__); ++ ++ info = calloc(1, sizeof(*info)); + if (!info) + return -1; ++ info->magic = MAGIC; ++ info->config = config; + +- dbg_printf(5, "[%s:%d %s]\n", __FILE__, __LINE__, __FUNCTION__); +- memset(info, 0, sizeof(*info)); ++ libvirt_init_libvirt_conf(info); + + #ifdef _MODULE +- if (sc_get(config, "fence_virtd/@debug", value, sizeof(value))==0) ++ if (sc_get(config, "fence_virtd/@debug", value, sizeof(value)) == 0) + dset(atoi(value)); + #endif + +- if (sc_get(config, "backends/libvirt/@uri", +- value, sizeof(value)) == 0) { +- uri = strdup(value); +- if (!uri) { +- free(info); +- return -1; +- } +- dbg_printf(1, "Using %s\n", uri); +- } +- +- /* We don't need to store the URI; we only use it once */ +- vp = virConnectOpen(uri); +- if (!vp) { +- free(uri); ++ if (info->vp_count < 1) { ++ dbg_printf(1, "[libvirt:INIT] Could not connect to any hypervisors\n"); ++ if (info->vp) ++ free(info->vp); + free(info); + return -1; + } +- free(uri); +- +- info->magic = MAGIC; +- info->vp = vp; + +- *c = (void *)info; ++ *c = (void *) info; + return 0; + } + +@@ -471,16 +313,19 @@ + libvirt_shutdown(backend_context_t c) + { + struct libvirt_info *info = (struct libvirt_info *)c; ++ int i; ++ int ret = 0; + + VALIDATE(info); + +- if (virConnectClose(info->vp) < 0) { +- free(info); +- return -errno; ++ for (i = 0 ; i < info->vp_count ; i++) { ++ if (virConnectClose(info->vp[i]) < 0) ++ ret = -errno; + } + ++ free(info->vp); + free(info); +- return 0; ++ return ret; + } + + +diff -ur a/server/virt.c b/server/virt.c +--- a/server/virt.c 2014-06-23 15:56:09.000000000 -0400 ++++ b/server/virt.c 2017-08-09 13:35:07.247875913 -0400 +@@ -1,5 +1,5 @@ + /* +- Copyright Red Hat, Inc. 2006 ++ 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 +@@ -16,7 +16,9 @@ + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. + */ ++ + #include ++#include + #include + #include + #include +@@ -24,8 +26,11 @@ + #include + #include + #include +-#include "virt.h" ++#include + ++#include "debug.h" ++#include "uuid-test.h" ++#include "virt.h" + + static int + _compare_virt(const void *_left, const void *_right) +@@ -37,96 +42,98 @@ + } + + +-virt_list_t *vl_get(virConnectPtr vp, int my_id) +-{ +- virt_list_t *vl = NULL; +- int d_count, x, saved_errno; +- virDomainPtr *dom_list; +- +- errno = EINVAL; +- if (!vp) +- return NULL; +- +- d_count = virConnectListAllDomains(vp, &dom_list, 0); +- if (d_count <= 0) +- goto out_fail; ++static void ++_free_dom_list(virDomainPtr *dom_list, int len) { ++ int x; + +- vl = malloc(sizeof(uint32_t) + sizeof(virt_state_t) * d_count); +- if (!vl) +- goto out_fail; ++ if (!dom_list || len <= 0) ++ return; ++ for (x = 0 ; x < len; x++) ++ virDomainFree(dom_list[x]); + +- vl->vm_count = d_count; ++ free(dom_list); ++} + +- /* Ok, we have the domain IDs - let's get their names and states */ +- for (x = 0; x < d_count; x++) { +- char *d_name; +- virDomainInfo d_info; +- char d_uuid[MAX_DOMAINNAME_LENGTH]; +- virDomainPtr dom = dom_list[x]; + +- if (!(d_name = (char *)virDomainGetName(dom))) +- goto out_fail; ++virt_list_t *vl_get(virConnectPtr *vp, int vp_count, int my_id) ++{ ++ virt_list_t *vl = NULL; ++ int d_count = 0; ++ int i; + +- if (virDomainGetUUIDString(dom, d_uuid) != 0) +- goto out_fail; ++ errno = EINVAL; ++ if (!vp || vp_count < 1) ++ return NULL; + +- if (virDomainGetInfo(dom, &d_info) < 0) +- goto out_fail; ++ 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; ++ ++ 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; ++ } + +- /* 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); + } + +- for (x = 0 ; x < d_count; x++) +- virDomainFree(dom_list[x]); +- free(dom_list); +- + /* 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; +- +-out_fail: +- saved_errno = errno; +- for (x = 0 ; x < d_count; x++) +- virDomainFree(dom_list[x]); +- free(dom_list); +- +- if (vl) +- free(vl); +- errno = saved_errno; +- return NULL; +-} +- +- +-/* Returns 0 if equal, nonzero if not */ +-int +-vl_cmp(virt_list_t *left, virt_list_t *right) +-{ +- int x; +- +- /* Quick checks */ +- if (!left->vm_count && !right->vm_count) +- return 1; +- if (left->vm_count != right->vm_count) +- return 0; +- +- for (x = 0; x < left->vm_count; x++) { +- if (strcmp(left->vm_states[x].v_name, +- right->vm_states[x].v_name)) +- return 1; +- /* +- if (left->vm_states[x].v_state.s_state != +- right->vm_states[x].v_state.s_state) +- return 1; +- */ +- } +- +- return 0; + } + + +@@ -192,3 +199,333 @@ + { + 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; ++} +diff -ur a/server/virt.h b/server/virt.h +--- a/server/virt.h 2014-06-23 15:56:09.000000000 -0400 ++++ b/server/virt.h 2017-08-09 13:30:40.709689288 -0400 +@@ -1,5 +1,5 @@ + /* +- Copyright Red Hat, Inc. 2006 ++ 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 +@@ -16,11 +16,13 @@ + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. + */ ++ + #ifndef _VIRT_H + #define _VIRT_H +-#include ++ + #include + #include ++#include + + #include "xvm.h" + +@@ -59,15 +61,16 @@ + virt_state_t vm_states[0]; + } virt_list_t; + +-virt_list_t *vl_get(virConnectPtr vp, int my_id); +- +-int vl_cmp(virt_list_t *left, virt_list_t *right); +- ++virt_list_t *vl_get(virConnectPtr *vp, int vp_count, int my_id); + void vl_print(virt_list_t *vl); + void vl_free(virt_list_t *old); +-virt_state_t * vl_find_uuid(virt_list_t *vl, const char *name); +-virt_state_t * vl_find_name(virt_list_t *vl, const char *name); ++virt_state_t *vl_find_uuid(virt_list_t *vl, const char *name); ++virt_state_t *vl_find_name(virt_list_t *vl, const char *name); + ++int vm_off(virConnectPtr *vp, int vp_count, const char *vm_name); ++int vm_on(virConnectPtr *vp, int vp_count, const char *vm_name); ++int vm_status(virConnectPtr *vp, int vp_count, const char *vm_name); ++int vm_reboot(virConnectPtr *vp, int vp_count, const char *vm_name); + + typedef void ckpt_handle; + int ckpt_read(void *hp, const char *secid, void *buf, size_t maxlen); diff --git a/SOURCES/bz1447700-virt_add_support_for_the_validate_all_status.patch b/SOURCES/bz1447700-virt_add_support_for_the_validate_all_status.patch new file mode 100644 index 0000000..ab46eee --- /dev/null +++ b/SOURCES/bz1447700-virt_add_support_for_the_validate_all_status.patch @@ -0,0 +1,110 @@ +diff -ur a/client/main.c b/client/main.c +--- a/client/main.c 2017-08-09 13:13:20.000846414 -0400 ++++ b/client/main.c 2017-08-09 13:09:04.294571613 -0400 +@@ -110,13 +110,17 @@ + } + + if (args.flags & F_ERR) { +- args_usage(argv[0], my_options, (argc == 1)); ++ if (args.op != FENCE_VALIDATEALL) ++ args_usage(argv[0], my_options, (argc == 1)); + exit(1); + } + ++ if (args.op == FENCE_VALIDATEALL) ++ exit(0); ++ + if (args.op == FENCE_METADATA) { + args_metadata(argv[0], my_options); +- return 0; ++ exit(0); + } + + if (args.delay > 0 && +diff -ur a/client/options.c b/client/options.c +--- a/client/options.c 2017-08-09 13:13:20.007846312 -0400 ++++ b/client/options.c 2017-08-09 13:11:23.464550208 -0400 +@@ -255,6 +255,8 @@ + args->op = FENCE_HOSTLIST; + } else if (!strcasecmp(value, "metadata")) { + args->op = FENCE_METADATA; ++ } else if (!strcasecmp(value, "validate-all")) { ++ args->op = FENCE_VALIDATEALL; + } else { + printf("Unsupported operation: %s\n", value); + args->flags |= F_ERR; +@@ -490,12 +492,12 @@ + { '\xff', NULL, "option", + /* Deprecated */ + 0, "string", "reboot", +- "Fencing option (null, off, on, [reboot], status, list, monitor, metadata)", ++ "Fencing option (null, off, on, [reboot], status, list, list-status, monitor, validate-all, metadata)", + assign_op }, + + { 'o', "-o ", "action", + 0, "string", "reboot", +- "Fencing action (null, off, on, [reboot], status, list, monitor, metadata)", ++ "Fencing action (null, off, on, [reboot], status, list, list-status, monitor, validate-all, metadata)", + assign_op }, + + { 'H', "-H ", "port", +@@ -799,7 +801,8 @@ + printf("\t\n"); + printf("\t\n"); + printf("\t\n"); +- printf("\t\n"); ++ printf("\t\n"); ++ printf("\t\n"); + printf("\n"); + printf("\n"); + } +diff -ur a/include/xvm.h b/include/xvm.h +--- a/include/xvm.h 2014-06-23 15:56:09.000000000 -0400 ++++ b/include/xvm.h 2017-08-09 13:09:04.295571598 -0400 +@@ -52,14 +52,15 @@ + #define DEFAULT_AUTH AUTH_SHA256 + + typedef enum { +- FENCE_NULL = 0x0, +- FENCE_OFF = 0x1, /* Turn the VM off */ +- FENCE_REBOOT = 0x2, /* Hit the reset button */ +- FENCE_ON = 0x3, /* Turn the VM on */ +- FENCE_STATUS = 0x4, /* virtual machine status (off/on) */ +- FENCE_DEVSTATUS = 0x5, /* Status of the fencing device */ +- FENCE_HOSTLIST = 0x6, /* List VMs controllable */ +- FENCE_METADATA = 0x7 ++ FENCE_NULL = 0x0, ++ FENCE_OFF = 0x1, /* Turn the VM off */ ++ FENCE_REBOOT = 0x2, /* Hit the reset button */ ++ FENCE_ON = 0x3, /* Turn the VM on */ ++ FENCE_STATUS = 0x4, /* virtual machine status (off/on) */ ++ FENCE_DEVSTATUS = 0x5, /* Status of the fencing device */ ++ FENCE_HOSTLIST = 0x6, /* List VMs controllable */ ++ FENCE_METADATA = 0x7, /* Print fence agent metadata */ ++ FENCE_VALIDATEALL = 0x8 /* Validate command-line or stdin arguments and exit */ + } fence_cmd_t; + + #define DEFAULT_TTL 4 +diff -ur a/man/fence_virt.8 b/man/fence_virt.8 +--- a/man/fence_virt.8 2014-06-23 15:56:09.000000000 -0400 ++++ b/man/fence_virt.8 2017-08-09 13:09:04.295571598 -0400 +@@ -145,7 +145,7 @@ + .TP + .B action + . +-Fencing action (null, off, on, reboot, status, monitor, list, or metadata) (Default Value: reboot). See the FENCING ACTIONS section. ++Fencing action (null, off, on, reboot, status, monitor, list, list-status, validate-all, or metadata) (Default Value: reboot). See the FENCING ACTIONS section. + + .TP + .B timeout +@@ -255,6 +255,10 @@ + on all backends). + + .TP ++\fBvalidate-all\fP ++Validate arguments given on either the command line or standard input. If validation fails, the fence agent will exit with code 1, otherwise it will exit with code 0. ++ ++.TP + \fBmetadata \fP + Print XML metadata to standard output. + diff --git a/SPECS/fence-virt.spec b/SPECS/fence-virt.spec index ee7cf80..bfeccdf 100644 --- a/SPECS/fence-virt.spec +++ b/SPECS/fence-virt.spec @@ -1,6 +1,6 @@ Name: fence-virt Version: 0.3.2 -Release: 12%{?dist} +Release: 13%{?dist} Summary: A pluggable fencing framework for virtual machines Group: System Environment/Base License: GPLv2+ @@ -23,6 +23,8 @@ Patch7: bz1393958-cleanup_numeric_argument_parsing.patch Patch8: bz1411910-fence_virtd_drop_legacy_sysvstartpriority_from_service.patch Patch9: bz1334170-cleanup_documentation_of_the_tcp_listener.patch Patch10: bz1092531-enable_hardening.patch +Patch11: bz1447700-virt_add_support_for_the_validate_all_status.patch +Patch12: bz1384181-make_the_libvirt_backend_survive_libvirtd.patch BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) @@ -106,6 +108,8 @@ machines on a desktop. %patch8 -p1 -b .bz1411910.1 %patch9 -p1 -b .bz1334170.1 %patch10 -p1 -b .bz1092531.1 +%patch11 -p1 -b .bz1447700.1 +%patch12 -p1 -b .bz1384181.1 %build %ifarch s390 s390x sparcv9 sparc64 @@ -209,6 +213,12 @@ fi %{_libdir}/%{name}/libvirt.so %changelog +* Wed Aug 09 2017 Ryan McCabe - 0.3.2-13 +- fence_virtd: Make the libvirt backend survive libvirtd restarts + Resolves: rhbz#1384181 +- fence_xvm/fence_virt: Add support for the validate-all status + Resolves: rhbz#1447700 + * Wed Jun 14 2017 Ryan McCabe - 0.3.2-12 - fence-virt: Rebuild to restore debuginfo Resolves: rhbz#1092531