[Cluster-devel] cluster/fence/agents/xvm Makefile fence_xvmd.c ...

lhh at sourceware.org lhh at sourceware.org
Tue Jun 26 17:23:42 UTC 2007


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 <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+
+
+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 <os> 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 "<bootloader>"
-#define ENDBOOTTAG   "</bootloader>"
-#define STARTOSTAG   "<os>"
-#define ENDOSTAG     "</os>"
-
-	/* 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 <os> 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 @@
+<domain type='xen' id='707'>
+  <name>pjc-xen-06</name>
+  <uuid>081b372c69a68432a13640fa03339353</uuid>
+  <os>
+    <type>hvm</type>
+    <loader>/usr/lib/xen/boot/hvmloader</loader>
+  </os>
+  <memory>524288</memory>
+  <vcpu>1</vcpu>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>restart</on_crash>
+  <features>
+    <pae/>
+  </features>
+  <devices>
+    <emulator>/usr/lib/xen/bin/qemu-dm</emulator>
+    <interface type='bridge'>
+      <source bridge='xenbr0'/>
+      <mac address='02:10:15:84:04:06'/>
+      <script path='vif-bridge'/>
+    </interface>
+    <disk type='file' device='disk'>
+      <driver name='file'/>
+      <source file='/root/pjc6'/>
+      <target dev='hda'/>
+    </disk>
+    <graphics type='vnc' port='5905'/>
+    <console tty='/dev/pts/5'/>
+  </devices>
+</domain>
+
--- cluster/fence/agents/xvm/tests/linux.xml	2007/06/26 17:17:40	1.1
+++ cluster/fence/agents/xvm/tests/linux.xml	2007/06/26 17:23:41	1.2
@@ -0,0 +1,31 @@
+<domain type='xen' id='2'>
+  <name>r5filebacked1</name>
+  <uuid>1a31981a01944fe7b7486a384e93dbae</uuid>
+  <bootloader>/usr/bin/pygrub</bootloader>
+  <os>
+    <type>linux</type>
+    <kernel>/var/lib/xen/boot_kernel.jGsgBH</kernel>
+    <initrd>/var/lib/xen/boot_ramdisk.bYFu-q</initrd>
+    <cmdline>ro root=/dev/VolGroup00/LogVol00</cmdline>
+  </os>
+  <memory>512000</memory>
+  <vcpu>1</vcpu>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>restart</on_crash>
+  <devices>
+    <interface type='bridge'>
+      <source bridge='xenbr0'/>
+      <mac address='C0:D1:F1:ED:1D:11'/>
+      <script path='vif-bridge'/>
+    </interface>
+    <graphics type='vnc' port='5900'/>
+    <disk type='file' device='disk'>
+      <driver name='tap' type='aio'/>
+      <source file='/mnt/xen/r5filebacked1'/>
+      <target dev='xvda'/>
+    </disk>
+    <console tty='/dev/pts/0'/>
+  </devices>
+</domain>
+




More information about the Cluster-devel mailing list