From mboxrd@z Thu Jan 1 00:00:00 1970 From: lhh@sourceware.org Date: 26 Jun 2007 17:23:42 -0000 Subject: [Cluster-devel] cluster/fence/agents/xvm Makefile fence_xvmd.c ... Message-ID: <20070626172342.30458.qmail@sourceware.org> List-Id: To: cluster-devel.redhat.com MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit CVSROOT: /cvs/cluster Module name: cluster Changes by: lhh at sourceware.org 2007-06-26 17:23:41 Modified files: fence/agents/xvm: Makefile fence_xvmd.c options.c options.h Added files: fence/agents/xvm: xml.c fence/agents/xvm/tests: hvm.xml linux.xml Log message: Fix full-virt rebooting (#243872); add local-only / no-cluster mode to fence_xvmd Patches: http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/xvm/xml.c.diff?cvsroot=cluster&r1=1.1&r2=1.2 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/xvm/Makefile.diff?cvsroot=cluster&r1=1.8&r2=1.9 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/xvm/fence_xvmd.c.diff?cvsroot=cluster&r1=1.8&r2=1.9 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/xvm/options.c.diff?cvsroot=cluster&r1=1.4&r2=1.5 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/xvm/options.h.diff?cvsroot=cluster&r1=1.2&r2=1.3 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/xvm/tests/hvm.xml.diff?cvsroot=cluster&r1=1.1&r2=1.2 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/xvm/tests/linux.xml.diff?cvsroot=cluster&r1=1.1&r2=1.2 --- cluster/fence/agents/xvm/xml.c 2007/06/26 17:17:40 1.1 +++ cluster/fence/agents/xvm/xml.c 2007/06/26 17:23:41 1.2 @@ -0,0 +1,306 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +xmlNodePtr +get_os_node(xmlDocPtr doc) +{ + xmlNodePtr node; + + /* Flip the property of the graphics port if it exists */ + node = xmlDocGetRootElement(doc); + node = node->children; + + while (node) { + if (!xmlStrcmp(node->name, (xmlChar *)"os")) + break; + node = node->next; + } + + return node; +} + + +int +flip_graphics_port(xmlDocPtr doc) +{ + xmlNodePtr node, curr; + + /* Flip the property of the graphics port if it exists */ + node = xmlDocGetRootElement(doc); + node = node->children; + + while (node) { + if (!xmlStrcmp(node->name, (xmlChar *)"devices")) + break; + node = node->next; + } + + node = node->children; + curr = node; + while (curr) { + if (!xmlStrcmp(curr->name, (xmlChar *)"graphics")) + break; + curr = curr->next; + } + + if (xmlGetProp(curr, (xmlChar *)"port")) { + printf("Zapping the port spec\n"); + xmlSetProp(curr, (xmlChar *)"port", (xmlChar *)"-1"); + } + + return 0; +} + + +int +cleanup_xml_doc(xmlDocPtr doc) +{ + xmlNodePtr os_node, curr; + int type = 0; + char *val; + + curr = xmlDocGetRootElement(doc); + if (xmlStrcmp(curr->name, (xmlChar *)"domain")) { + printf("Invalid XML\n"); + return -1; + } + + flip_graphics_port(doc); + + os_node = get_os_node(doc); + + curr = os_node->children; + while (curr) { + if (!xmlStrcmp(curr->name, (xmlChar *)"type")) + break; + curr = curr->next; + } + if (!curr) { + printf("Unable to determine the domain type\n"); + return -1; + } + + val = (char *)xmlNodeGetContent(curr); + while (isspace(*val)) val++; + + if (!strcasecmp(val, "hvm")) { + type = 1; + printf("Virtual machine is HVM\n"); + } else if (!strcasecmp(val, "linux")) { + type = 2; + printf("Virtual machine is Linux\n"); + } + + /* Node is still pointing to the block */ + if (type == 2) { + printf("Unlinkiking %s block\n", (char *)os_node->name); + xmlUnlinkNode(os_node); + xmlFreeNode(os_node); + } + + return 0; +} + + +int +xtree_readfile(const char *filename, xmlDocPtr *xtreep) +{ + xmlNodePtr cur; + + xmlKeepBlanksDefault(0); + xmlIndentTreeOutput = 1; + + *xtreep = xmlParseFile(filename); + + if (!*xtreep) + return -1; + + if (!((cur = xmlDocGetRootElement(*xtreep)))) { + xmlFreeDoc(*xtreep); + *xtreep = NULL; + return -1; + } + + return 0; +} + + +int +xtree_readbuffer(const char *buffer, size_t size, xmlDocPtr *xtreep) +{ + xmlNodePtr cur; + + xmlKeepBlanksDefault(0); + xmlIndentTreeOutput = 1; + + *xtreep = xmlParseMemory(buffer, size); + + if (!*xtreep) { + printf("parse failure %p %d\n", buffer, (int)size); + return -1; + } + + if (!((cur = xmlDocGetRootElement(*xtreep)))) { + printf("root element failure\n"); + xmlFreeDoc(*xtreep); + *xtreep = NULL; + return -1; + } + + return 0; +} + + +int +xtree_writefile(const char *filename, xmlDocPtr xtree) +{ + char tmpfn[1024]; + int fd, tmpfd; + xmlChar *buffer; + struct flock flock; + int n, remain, written, size = 0; + + snprintf(tmpfn, sizeof(tmpfn), "%s.XXXXXX", filename); + tmpfd = mkstemp(tmpfn); + if (tmpfd == -1) + return -1; + + memset(&flock, 0, sizeof(flock)); + flock.l_type = F_WRLCK; + + fd = open(filename, O_WRONLY | O_CREAT | O_SYNC); + if (fd == -1) { + n = errno; + close(tmpfd); + unlink(tmpfn); + errno = n; + return -1; + } + + while (fcntl(fd, F_SETLKW, &flock) == -1) { + if (errno == EINTR) + continue; + n = errno; + close(fd); + close(tmpfd); + unlink(tmpfn); + errno = n; + return -1; + } + + xmlDocDumpFormatMemory(xtree, (xmlChar **)&buffer, (int *)&size, 1); + + written = 0; + remain = size; + while (remain) { + n = write(tmpfd, buffer + written, remain); + + if (n == -1) { + if (errno == EINTR) + continue; + + free(buffer); + n = errno; + close(fd); + close(tmpfd); + unlink(tmpfn); + errno = n; + return -1; + } + + written += n; + remain -= n; + } + + xmlFree(buffer); + if (rename(tmpfn, filename) == -1) { + n = errno; + close(fd); + close(tmpfd); + unlink(tmpfn); + errno = n; + return -1; + } + + close(fd); + fsync(tmpfd); + close(tmpfd); + return 0; +} + + +int +xtree_writebuffer(xmlDocPtr xtree, char **buffer, size_t *size) +{ + *size = 0; + xmlDocDumpFormatMemory(xtree, (xmlChar **)buffer, (int *)size, 1); + return 0; +} + + +int +cleanup_xml(char *desc, char **ret, size_t *retsz) +{ + xmlDocPtr xtree; + int rv; + + *ret = NULL; + if (xtree_readbuffer(desc, strlen(desc), &xtree) < 0) { + xmlCleanupParser(); + return -1; + } + + rv = cleanup_xml_doc(xtree); + if (xtree_writebuffer(xtree, ret, retsz) < 0) + rv = -1; + + if (*ret && rv < 0) + free(*ret); + xmlFreeDoc(xtree); + xmlCleanupParser(); + return rv; +} + + +#ifdef STANDALONE +int +main(int argc, char **argv) +{ + char *file = NULL; + char *buf; + size_t sz; + int opt; + xmlDocPtr xtree; + + while ((opt = getopt(argc, argv, "f:")) != EOF) { + switch(opt) { + case 'f': + file = optarg; + break; + } + } + + if (!file) { + printf("No file specified\n"); + return 1; + } + + if (xtree_readfile(file, &xtree) < 0) + return -1; + + cleanup_xml_doc(xtree); + + xtree_writebuffer(xtree, &buf, &sz); + write(1, buf, sz); + + return 0; +} +#endif --- cluster/fence/agents/xvm/Makefile 2007/06/01 09:45:32 1.8 +++ cluster/fence/agents/xvm/Makefile 2007/06/26 17:23:41 1.9 @@ -22,7 +22,8 @@ OBJS2= fence_xvmd.o \ virt.o \ options-ccs.o \ - vm_states.o + vm_states.o \ + xml.o SHAREDOBJS= mcast.o \ simple_auth.o \ @@ -35,12 +36,14 @@ CFLAGS += -I${ccsincdir} -I${cmanincdir} -I${openaisincdir} CFLAGS += -I${virtincdir} -I${nssincdir} -I${nsprincdir} CFLAGS += -I${incdir} +CFLAGS += `xml2-config --cflags` LDFLAGS += -L${ccslibdir} -L${cmanlibdir} -L${dlmlibdir} LDFLAGS += -L${nsslibdir} -L${nsprlibdir} -L${libdir} -LDFLAGS += -lccs -lcman -ldlm -lnss3 -lnspr4 +LDFLAGS += -lccs -lcman -ldlm -lnss3 -lnspr4 EXTRA_LDFLAGS += -L${virtlibdir} -lvirt -L${openaislibdir} -lSaCkpt +EXTRA_LDFLAGS += `xml2-config --libs` all: ${TARGET1} ${TARGET2} @@ -56,6 +59,10 @@ clean: rm -f ${TARGET1} ${TARGET2} *~ *.o +testprog: + gcc -o testprog xml.c -I/usr/include/libxml2 -lxml2 \ + -DSTANDALONE -ggdb + install: all if [ ! -d ${sbindir} ]; then \ install -d ${sbindir}; \ --- cluster/fence/agents/xvm/fence_xvmd.c 2007/01/10 20:30:47 1.8 +++ cluster/fence/agents/xvm/fence_xvmd.c 2007/06/26 17:23:41 1.9 @@ -55,6 +55,9 @@ static int running = 1; + +int cleanup_xml(char *xmldesc, char **ret, size_t *retsz); + int connect_tcp(fence_req_t *req, fence_auth_type_t auth, void *key, size_t key_len) @@ -165,48 +168,6 @@ } -/* - Nuke the OS block if this domain was booted using a bootloader. - XXX We probably should use libxml2 to do this, but this is very fast - */ -void -cleanup_xmldesc(char *xmldesc) -{ - char *start = NULL; - char *end = NULL; - -#define STARTBOOTTAG "" -#define ENDBOOTTAG "" -#define STARTOSTAG "" -#define ENDOSTAG "" - - /* Part 1: Check for a boot loader */ - start = strcasestr(xmldesc, STARTBOOTTAG); - if (start) { - start += strlen(STARTBOOTTAG); - end = strcasestr(start, ENDBOOTTAG); - if (end == start) { - /* Empty bootloader tag -> return */ - return; - } - } - - /* Part 2: Nuke the tag */ - start = strcasestr(xmldesc, STARTOSTAG); - if (!start) - return; - end = strcasestr(start, ENDOSTAG); - if (!end) - return; - end += strlen(ENDOSTAG); - - dprintf(3, "Clearing %d bytes starting @ %p\n", (int)(end-start), - start); - - memset(start, ' ', end-start); -} - - static inline int wait_domain(fence_req_t *req, virConnectPtr vp, int timeout) { @@ -262,7 +223,8 @@ int fd, ret = -1; virDomainPtr vdp; char response = 1; - char *domain_desc; + char *domain_desc, *domain_desc_sanitized; + size_t sz; if (!(vdp = get_domain(req, vp))) { dprintf(2, "Could not find domain: %s\n", req->domain); @@ -305,7 +267,14 @@ if (domain_desc) { dprintf(3, "[[ XML Domain Info ]]\n"); dprintf(3, "%s\n[[ XML END ]]\n", domain_desc); - cleanup_xmldesc(domain_desc); + + sz = 0; + if (cleanup_xml(domain_desc, + &domain_desc_sanitized, &sz) == 0) { + free(domain_desc); + domain_desc = domain_desc_sanitized; + } + dprintf(3, "[[ XML Domain Info (modified) ]]\n"); dprintf(3, "%s\n[[ XML END ]]\n", domain_desc); } else { @@ -431,7 +400,7 @@ if (!hp || !domain || !state || !strlen((char *)domain)) return -1; - if (!strcmp("Domain-0", (char *)domain)) + if (!strcmp(DOMAIN0NAME, (char *)domain)) return -1; return ckpt_read(hp, (char *)domain, state, sizeof(*state)); @@ -564,10 +533,10 @@ struct sockaddr_in sin; int len; int n; - int my_id; + int my_id = 1; socklen_t slen; fence_req_t data; - virConnectPtr vp; + virConnectPtr vp = NULL; virt_list_t *vl = NULL; virt_state_t *dom = NULL; @@ -575,7 +544,9 @@ if (!vp) perror("virConnectOpen"); - get_cman_ids(ch, &my_id, NULL); + if (!(args->flags & F_NOCLUSTER)) + get_cman_ids(ch, &my_id, NULL); + printf("My Node ID = %d\n", my_id); if (vp) { @@ -615,11 +586,14 @@ /* Update list of VMs from libvirt. */ virt_list_update(vp, &vl, my_id); vl_print(vl); + /* Store information here */ - if (args->flags & F_USE_UUID) - store_domains_by_uuid(h, vl); - else - store_domains_by_name(h, vl); + if (!(args->flags & F_NOCLUSTER)) { + if (args->flags & F_USE_UUID) + store_domains_by_uuid(h, vl); + else + store_domains_by_name(h, vl); + } /* * If no requests, we're done @@ -661,7 +635,7 @@ dom = vl_find_uuid(vl, (char *)data.domain); else dom = vl_find_name(vl, (char *)data.domain); - if (!dom) { + if (!dom && !(args->flags & F_NOCLUSTER)) { handle_remote_domain(ch, h, &data, args->auth, key, key_len, my_id); continue; @@ -702,8 +676,8 @@ int mc_sock; char key[4096]; int key_len = 0, x; - char *my_options = "dfi:a:p:C:c:k:u?hV"; - cman_handle_t ch; + char *my_options = "dfi:a:p:C:c:k:u?hLXV"; + cman_handle_t ch = NULL; void *h; args_init(&args); @@ -735,8 +709,10 @@ if (args.auth != AUTH_NONE || args.hash != HASH_NONE) { key_len = read_key_file(args.key_file, key, sizeof(key)); if (key_len < 0) { - printf("Could not read key file\n"); - return 1; + printf("Could not read %s; operating without " + "authentication\n", args.key_file); + args.auth = AUTH_NONE; + args.hash = HASH_NONE; } } @@ -758,32 +734,34 @@ return 1; } - /* Wait for cman to start. */ - x = 0; - while ((ch = cman_init(NULL)) == NULL) { - if (!x) { - printf("Could not connect to CMAN; retrying...\n"); - x = 1; - } - sleep(3); - } - if (x) - printf("Connected to CMAN\n"); - /* Wait for quorum */ - while (!cman_is_quorate(ch)) - sleep(3); - - /* Wait for openais checkpointing to become available */ - x = 0; - while ((h = ckpt_init("vm_states", 262144, 4096, 64, 10)) == NULL) { - if (!x) { - printf("Could not initialize saCkPt; retrying...\n"); - x = 1; + if (!(args.flags & F_NOCLUSTER)) { + /* Wait for cman to start. */ + x = 0; + while ((ch = cman_init(NULL)) == NULL) { + if (!x) { + printf("Could not connect to CMAN; retrying...\n"); + x = 1; + } + sleep(3); + } + if (x) + printf("Connected to CMAN\n"); + /* Wait for quorum */ + while (!cman_is_quorate(ch)) + sleep(3); + + /* Wait for openais checkpointing to become available */ + x = 0; + while ((h = ckpt_init("vm_states", 262144, 4096, 64, 10)) == NULL) { + if (!x) { + printf("Could not initialize saCkPt; retrying...\n"); + x = 1; + } + sleep(3); } - sleep(3); + if (x) + printf("Checkpoint initialized\n"); } - if (x) - printf("Checkpoint initialized\n"); if (args.family == PF_INET) mc_sock = ipv4_recv_sk(args.addr, args.port); --- cluster/fence/agents/xvm/options.c 2006/11/30 21:15:00 1.4 +++ cluster/fence/agents/xvm/options.c 2007/06/26 17:23:41 1.5 @@ -253,6 +253,13 @@ } +static inline void +assign_nocluster(fence_xvm_args_t *args, struct arg_info *arg, char *value) +{ + args->flags |= F_NOCLUSTER; +} + + /** ALL valid command line and stdin arguments for this fencing agent */ static struct arg_info _arg_info[] = { { '\xff', NULL, "agent", @@ -326,6 +333,10 @@ { 'X', "-X", NULL, "Do not connect to CCS for configuration", assign_noccs }, + + { 'L', "-L", NULL, + "Local mode only (no cluster)", + assign_nocluster }, { 'V', "-V", NULL, "Display version and exit", --- cluster/fence/agents/xvm/options.h 2006/11/13 16:13:50 1.2 +++ cluster/fence/agents/xvm/options.h 2007/06/26 17:23:41 1.3 @@ -27,7 +27,8 @@ F_USE_UUID = 0x10, F_VERSION = 0x20, F_CCSERR = 0x40, - F_CCSFAIL = 0x80 + F_CCSFAIL = 0x80, + F_NOCLUSTER = 0x100 } arg_flags_t; --- cluster/fence/agents/xvm/tests/hvm.xml 2007/06/26 17:17:40 1.1 +++ cluster/fence/agents/xvm/tests/hvm.xml 2007/06/26 17:23:41 1.2 @@ -0,0 +1,32 @@ + + pjc-xen-06 + 081b372c69a68432a13640fa03339353 + + hvm + /usr/lib/xen/boot/hvmloader + + 524288 + 1 + destroy + restart + restart + + + + + /usr/lib/xen/bin/qemu-dm + + + +