[Libvir] PATCH 2/2: Support QEMU (+KVM) in libvirt
Daniel P. Berrange
berrange at redhat.com
Fri Jan 5 21:18:53 UTC 2007
The attached patch provides a new driver backend for libvirt which allows
management of QEMU instances by talking to the libvirt QEMU daemon. It
basically just marshalls libvirt API calls onto the wire & de-marshalls
the reply. All the interesting functionality stuff is in the daemon.
Dan.
--
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=|
|=- Perl modules: http://search.cpan.org/~danberr/ -=|
|=- Projects: http://freshmeat.net/~danielpb/ -=|
|=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
-------------- next part --------------
? qemud
Index: Makefile.am
===================================================================
RCS file: /data/cvs/libvirt/Makefile.am,v
retrieving revision 1.12
diff -u -p -r1.12 Makefile.am
--- Makefile.am 21 Sep 2006 15:24:37 -0000 1.12
+++ Makefile.am 5 Jan 2007 21:09:06 -0000
@@ -1,6 +1,6 @@
## Process this file with automake to produce Makefile.in
-SUBDIRS = src include docs @PYTHON_SUBDIR@ tests proxy po
+SUBDIRS = src qemud proxy include docs @PYTHON_SUBDIR@ tests po
ACLOCAL_AMFLAGS = -I m4
Index: configure.in
===================================================================
RCS file: /data/cvs/libvirt/configure.in,v
retrieving revision 1.50
diff -u -p -r1.50 configure.in
--- configure.in 20 Dec 2006 14:54:25 -0000 1.50
+++ configure.in 5 Jan 2007 21:09:06 -0000
@@ -266,6 +266,7 @@ AC_OUTPUT(Makefile src/Makefile include/
po/Makefile.in \
include/libvirt/Makefile include/libvirt/libvirt.h \
python/Makefile python/tests/Makefile \
+ qemud/Makefile \
tests/Makefile proxy/Makefile \
tests/xml2sexprdata/Makefile \
tests/sexpr2xmldata/Makefile \
Index: include/libvirt/virterror.h
===================================================================
RCS file: /data/cvs/libvirt/include/libvirt/virterror.h,v
retrieving revision 1.17
diff -u -p -r1.17 virterror.h
--- include/libvirt/virterror.h 8 Nov 2006 16:55:20 -0000 1.17
+++ include/libvirt/virterror.h 5 Jan 2007 21:09:06 -0000
@@ -46,7 +46,8 @@ typedef enum {
VIR_FROM_DOM, /* Error when operating on a domain */
VIR_FROM_RPC, /* Error in the XML-RPC code */
VIR_FROM_PROXY, /* Error in the proxy code */
- VIR_FROM_CONF /* Error in the configuration file handling */
+ VIR_FROM_CONF, /* Error in the configuration file handling */
+ VIR_FROM_QEMUD, /* Error at the QEMU daemon */
} virErrorDomain;
Index: src/Makefile.am
===================================================================
RCS file: /data/cvs/libvirt/src/Makefile.am,v
retrieving revision 1.30
diff -u -p -r1.30 Makefile.am
--- src/Makefile.am 16 Nov 2006 19:06:13 -0000 1.30
+++ src/Makefile.am 5 Jan 2007 21:09:07 -0000
@@ -1,7 +1,8 @@
## Process this file with automake to produce Makefile.in
-INCLUDES = -I$(top_builddir)/include -I at top_srcdir@/include @LIBXML_CFLAGS@ \
+INCLUDES = -I$(top_builddir)/include -I at top_srcdir@/include @LIBXML_CFLAGS@ -I at top_srcdir@/qemud \
-DBINDIR=\""$(libexecdir)"\" -DLOCALEBASEDIR=\""$(datadir)/locale"\" \
+ -DLOCALSTATEDIR=\""$(localstatedir)"\" \
-DGETTEXT_PACKAGE=\"$(PACKAGE)\"
DEPS = libvirt.la
LDADDS = @STATIC_BINARIES@ libvirt.la
@@ -28,7 +29,8 @@ libvirt_la_SOURCES = \
driver.h \
proxy_internal.c proxy_internal.h \
conf.c conf.h \
- xm_internal.c xm_internal.h
+ xm_internal.c xm_internal.h \
+ qemud_internal.c qemud_internal.h
bin_PROGRAMS = virsh
Index: src/driver.h
===================================================================
RCS file: /data/cvs/libvirt/src/driver.h,v
retrieving revision 1.15
diff -u -p -r1.15 driver.h
--- src/driver.h 22 Nov 2006 17:48:29 -0000 1.15
+++ src/driver.h 5 Jan 2007 21:09:07 -0000
@@ -22,7 +22,8 @@ typedef enum {
VIR_DRV_XEN_DAEMON = 3,
VIR_DRV_TEST = 4,
VIR_DRV_XEN_PROXY = 5,
- VIR_DRV_XEN_XM = 6
+ VIR_DRV_XEN_XM = 6,
+ VIR_DRV_QEMUD = 7
} virDrvNo;
Index: src/libvirt.c
===================================================================
RCS file: /data/cvs/libvirt/src/libvirt.c,v
retrieving revision 1.51
diff -u -p -r1.51 libvirt.c
--- src/libvirt.c 22 Nov 2006 17:48:29 -0000 1.51
+++ src/libvirt.c 5 Jan 2007 21:09:07 -0000
@@ -32,6 +32,7 @@
#include "proxy_internal.h"
#include "xml.h"
#include "test.h"
+#include "qemud_internal.h"
/*
* TODO:
@@ -79,6 +80,7 @@ virInitialize(void)
xenStoreRegister();
xenXMRegister();
testRegister();
+ qemudRegister();
return(0);
}
@@ -441,6 +443,7 @@ virConnectGetVersion(virConnectPtr conn,
return(0);
}
}
+
return (-1);
}
Index: src/qemud_internal.c
===================================================================
RCS file: src/qemud_internal.c
diff -N src/qemud_internal.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/qemud_internal.c 5 Jan 2007 21:09:07 -0000
@@ -0,0 +1,896 @@
+/*
+ * qemud_internal.c: A backend for managing QEMU machines
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange at redhat.com>
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+#include <libxml/uri.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <limits.h>
+#include <paths.h>
+
+#include "internal.h"
+#include "qemud_internal.h"
+#include "xml.h"
+#include "protocol.h"
+
+int qemudOpen(virConnectPtr conn,
+ const char *name,
+ int flags);
+int qemudClose (virConnectPtr conn);
+int qemudGetVersion(virConnectPtr conn,
+ unsigned long *hvVer);
+int qemudNodeGetInfo(virConnectPtr conn,
+ virNodeInfoPtr info);
+int qemudNumOfDomains(virConnectPtr conn);
+int qemudListDomains(virConnectPtr conn,
+ int *ids,
+ int maxids);
+int qemudNumOfDefinedDomains(virConnectPtr conn);
+int qemudListDefinedDomains(virConnectPtr conn,
+ const char **names,
+ int maxnames);
+virDomainPtr
+qemudDomainCreateLinux(virConnectPtr conn, const char *xmlDesc,
+ unsigned int flags);
+virDomainPtr qemudLookupDomainByID(virConnectPtr conn,
+ int id);
+virDomainPtr qemudLookupDomainByUUID(virConnectPtr conn,
+ const unsigned char *uuid);
+virDomainPtr qemudLookupDomainByName(virConnectPtr conn,
+ const char *name);
+int qemudShutdownDomain(virDomainPtr domain);
+int qemudDestroyDomain(virDomainPtr domain);
+int qemudResumeDomain(virDomainPtr domain);
+int qemudPauseDomain(virDomainPtr domain);
+int qemudGetDomainInfo(virDomainPtr domain,
+ virDomainInfoPtr info);
+char * qemudDomainDumpXML(virDomainPtr domain, int flags);
+int qemudSaveDomain(virDomainPtr domain, const char *file);
+int qemudRestoreDomain(virConnectPtr conn, const char *file);
+int qemudDomainCreate(virDomainPtr conn);
+virDomainPtr qemudDomainDefineXML(virConnectPtr conn, const char *xml);
+int qemudUndefine(virDomainPtr dom);
+
+static virDriver qemudDriver = {
+ VIR_DRV_QEMUD,
+ "QEMUD",
+ LIBVIR_VERSION_NUMBER,
+ NULL, /* init */
+ qemudOpen, /* open */
+ qemudClose, /* close */
+ NULL, /* type */
+ qemudGetVersion, /* version */
+ qemudNodeGetInfo, /* nodeGetInfo */
+ qemudListDomains, /* listDomains */
+ qemudNumOfDomains, /* numOfDomains */
+ qemudDomainCreateLinux, /* domainCreateLinux */
+ qemudLookupDomainByID, /* domainLookupByID */
+ qemudLookupDomainByUUID, /* domainLookupByUUID */
+ qemudLookupDomainByName, /* domainLookupByName */
+ qemudPauseDomain, /* domainSuspend */
+ qemudResumeDomain, /* domainResume */
+ qemudShutdownDomain, /* domainShutdown */
+ NULL, /* domainReboot */
+ qemudDestroyDomain, /* domainDestroy */
+ NULL, /* domainFree */
+ NULL, /* domainGetName */
+ NULL, /* domainGetID */
+ NULL, /* domainGetUUID */
+ NULL, /* domainGetOSType */
+ NULL, /* domainGetMaxMemory */
+ NULL, /* domainSetMaxMemory */
+ NULL, /* domainSetMemory */
+ qemudGetDomainInfo, /* domainGetInfo */
+ qemudSaveDomain, /* domainSave */
+ qemudRestoreDomain, /* domainRestore */
+ NULL, /* domainCoreDump */
+ NULL, /* domainSetVcpus */
+ NULL, /* domainPinVcpu */
+ NULL, /* domainGetVcpus */
+ qemudDomainDumpXML, /* domainDumpXML */
+ qemudListDefinedDomains, /* listDomains */
+ qemudNumOfDefinedDomains, /* numOfDomains */
+ qemudDomainCreate, /* domainCreate */
+ qemudDomainDefineXML, /* domainDefineXML */
+ qemudUndefine, /* domainUndefine */
+ NULL, /* domainAttachDevice */
+ NULL, /* domainDetachDevice */
+};
+
+
+static void
+qemudError(virConnectPtr con,
+ virDomainPtr dom,
+ virErrorNumber error,
+ const char *info)
+{
+ const char *errmsg;
+
+ if (error == VIR_ERR_OK)
+ return;
+
+ errmsg = __virErrorMsg(error, info);
+ __virRaiseError(con, dom, VIR_FROM_QEMUD, error, VIR_ERR_ERROR,
+ errmsg, info, NULL, 0, 0, errmsg, info, 0);
+}
+
+static void qemudPacketError(virConnectPtr con,
+ virDomainPtr dom,
+ struct qemud_packet *pkt) {
+ if (!pkt) {
+ qemudError(con, dom, VIR_ERR_INTERNAL_ERROR, "Malformed data packet");
+ return;
+ }
+ if (pkt->header.type == QEMUD_PKT_FAILURE) {
+ /* Paranoia in case remote side didn't terminate it */
+ if (pkt->data.failureReply.message[0])
+ pkt->data.failureReply.message[QEMUD_MAX_ERROR_LEN-1] = '\0';
+
+ qemudError(con, dom, pkt->data.failureReply.code,
+ pkt->data.failureReply.message[0] ?
+ pkt->data.failureReply.message : NULL);
+ } else {
+ qemudError(con, dom, VIR_ERR_INTERNAL_ERROR, "Incorrect reply type");
+ }
+}
+
+void qemudRegister(void) {
+ virRegisterDriver(&qemudDriver);
+}
+
+/**
+ * qemudFindServerPath:
+ *
+ * Tries to find the path to the qemud binary.
+ *
+ * Returns path on success or NULL in case of error.
+ */
+static const char *
+qemudFindServerPath(void)
+{
+ static const char *serverPaths[] = {
+ BINDIR "/libvirt_qemud",
+ BINDIR "/libvirt_qemud_dbg",
+ NULL
+ };
+ int i;
+ const char *debugQemuD = getenv("LIBVIRT_QEMUD_SERVER");
+
+ if (debugQemuD)
+ return(debugQemuD);
+
+ for (i = 0; serverPaths[i]; i++) {
+ if (access(serverPaths[i], X_OK | R_OK) == 0) {
+ return serverPaths[i];
+ }
+ }
+ return NULL;
+}
+
+
+/**
+ * qemudForkServer:
+ *
+ * Forks and try to launch the qemud server
+ *
+ * Returns 0 in case of success or -1 in case of detected error.
+ */
+static int
+qemudForkServer(const char *path)
+{
+ const char *proxyPath = qemudFindServerPath();
+ int ret, pid, status;
+
+ if (!proxyPath) {
+ fprintf(stderr, "failed to find qemud\n");
+ return(-1);
+ }
+
+ /* Become a daemon */
+ pid = fork();
+ if (pid == 0) {
+ int stdinfd = -1;
+ int stdoutfd = -1;
+ int i;
+ if ((stdinfd = open(_PATH_DEVNULL, O_RDONLY)) < 0)
+ goto cleanup;
+ if ((stdoutfd = open(_PATH_DEVNULL, O_WRONLY)) < 0)
+ goto cleanup;
+ if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO)
+ goto cleanup;
+ if (dup2(stdoutfd, STDOUT_FILENO) != STDOUT_FILENO)
+ goto cleanup;
+ if (dup2(stdoutfd, STDERR_FILENO) != STDERR_FILENO)
+ goto cleanup;
+ if (close(stdinfd) < 0)
+ goto cleanup;
+ stdinfd = -1;
+ if (close(stdoutfd) < 0)
+ goto cleanup;
+ stdoutfd = -1;
+
+ int open_max = sysconf (_SC_OPEN_MAX);
+ for (i = 0; i < open_max; i++)
+ if (i != STDIN_FILENO &&
+ i != STDOUT_FILENO &&
+ i != STDERR_FILENO)
+ close(i);
+
+ setsid();
+ if (fork() == 0) {
+ /* Run daemon in auto-shutdown mode, so it goes away when
+ no longer needed by an active guest, or client */
+ execl(proxyPath, proxyPath, "--listen", path, "--timeout", "30", NULL);
+ fprintf(stderr, "failed to exec %s\n", proxyPath);
+ }
+ /*
+ * calling exit() generate troubles for termination handlers
+ */
+ _exit(0);
+
+ cleanup:
+ if (stdoutfd != -1)
+ close(stdoutfd);
+ if (stdinfd != -1)
+ close(stdinfd);
+ _exit(-1);
+ }
+
+ /*
+ * do a waitpid on the intermediate process to avoid zombies.
+ */
+ retry_wait:
+ ret = waitpid(pid, &status, 0);
+ if (ret < 0) {
+ if (errno == EINTR)
+ goto retry_wait;
+ }
+
+ return (0);
+}
+
+/**
+ * qemudOpenClientUNIX:
+ * @path: the fileame for the socket
+ *
+ * try to connect to the socket open by qemud
+ *
+ * Returns the associated file descriptor or -1 in case of failure
+ */
+static int
+qemudOpenClientUNIX(const char *path, int autostart) {
+ int fd;
+ struct sockaddr_un addr;
+ int trials = 0;
+
+ retry:
+ fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0) {
+ return(-1);
+ }
+
+ /*
+ * Abstract socket do not hit the filesystem, way more secure and
+ * garanteed to be atomic
+ */
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ addr.sun_path[0] = '\0';
+ strncpy(&addr.sun_path[1], path, sizeof(addr.sun_path) - 2);
+
+ /*
+ * now bind the socket to that address and listen on it
+ */
+ if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ close(fd);
+ if (autostart && trials < 3) {
+ addr.sun_path[0] = '@'; /* We can't pass actual nulls around */
+ if (qemudForkServer(addr.sun_path) < 0)
+ return(-1);
+ trials++;
+ usleep(5000 * trials * trials);
+ goto retry;
+ }
+ return (-1);
+ }
+
+ return (fd);
+}
+
+/**
+ * qemudOpenClientAddr:
+ * @addr: the address of the host
+ *
+ * try to connect to the socket open by qemud
+ *
+ * Returns the associated file descriptor or -1 in case of failure
+ */
+static int
+qemudOpenClientAddr(const char *addr, int port) {
+ int fd = -1;
+ struct addrinfo *ai;
+ struct addrinfo hints;
+ struct addrinfo *tmp;
+ char service[30];
+
+ if (port == 0)
+ strcpy(service, QEMUD_DEFAULT_PORT_STR);
+ else
+ snprintf(service, sizeof(service)-1, "%d", port);
+
+ memset (&hints, '\0', sizeof (hints));
+ hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
+ hints.ai_socktype = SOCK_STREAM;
+
+ if (getaddrinfo (addr, service, &hints, &ai) < 0)
+ return -1;
+
+ tmp = ai;
+ while (tmp) {
+ if ((fd = socket(tmp->ai_family, tmp->ai_socktype,
+ tmp->ai_protocol)) < 0)
+ break;
+
+ if (connect(fd, tmp->ai_addr, tmp->ai_addrlen) == 0)
+ break;
+
+ close(fd);
+ fd = -1;
+ tmp = tmp->ai_next;
+ }
+
+ freeaddrinfo(ai);
+
+ return fd;
+}
+
+
+
+/* Takes a single request packet, does a blocking send on it.
+ * then blocks until the complete reply has come back, or
+ * connection closes.
+ */
+static int qemudProcessRequest(virConnectPtr conn,
+ virDomainPtr dom,
+ struct qemud_packet *req,
+ struct qemud_packet *reply) {
+ char *out = (char *)req;
+ int outDone = 0;
+ int outLeft = sizeof(struct qemud_packet_header) + req->header.dataSize;
+ char *in = (char *)reply;
+ int inGot = 0;
+ int inLeft = sizeof(struct qemud_packet_header);
+
+ //printf("Send request %d\n", req->header.type);
+
+ // Block sending entire outgoing packet
+ while (outLeft) {
+ int got = write(conn->handle, out+outDone, outLeft);
+ if (got < 0) {
+ return -1;
+ }
+ outDone += got;
+ outLeft -= got;
+ }
+
+ /* Block waiting for header to come back */
+ while (inLeft) {
+ int done = read(conn->handle, in+inGot, inLeft);
+ if (done <= 0) {
+ return -1;
+ }
+ inGot += done;
+ inLeft -= done;
+ }
+
+ /* Validate header isn't bogus (bigger than
+ maximum defined packet size) */
+ if (reply->header.dataSize > sizeof(union qemud_packet_data)) {
+ printf("Got type %ds body %d (max %ld)\n", reply->header.type, reply->header.dataSize, sizeof(union qemud_packet_data));
+ printf("%ld == %ld + %ld\n", sizeof(struct qemud_packet), sizeof(struct qemud_packet_header), sizeof(union qemud_packet_data));
+ qemudPacketError(conn, dom, NULL);
+ return -1;
+ }
+
+ /* Now block reading in body */
+ inLeft = reply->header.dataSize;
+ while (inLeft) {
+ int done = read(conn->handle, in+inGot, inLeft);
+ if (done <= 0) {
+ return -1;
+ }
+ inGot += done;
+ inLeft -= done;
+ }
+
+ if (reply->header.type != req->header.type) {
+ qemudPacketError(conn, dom, reply);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Open a connection to the libvirt QEMU daemon
+ */
+static int qemudOpenConnection(xmlURIPtr uri, int readonly) {
+
+ if (uri->server == NULL) {
+ if (!strcmp(uri->path, "/system")) {
+ if (readonly)
+ return qemudOpenClientUNIX(LOCALSTATEDIR "/run/qemud-ro", 0);
+ else
+ return qemudOpenClientUNIX(LOCALSTATEDIR "/run/qemud", 0);
+ } else if (!strcmp(uri->path, "/session")) {
+ char path[PATH_MAX];
+ struct passwd *pw;
+ int uid;
+
+ if ((uid = geteuid()) < 0) {
+ return -1;
+ }
+
+ if (!(pw = getpwuid(uid)))
+ return -1;
+
+ if (snprintf(path, PATH_MAX, "%s/.qemud.d/sock", pw->pw_dir) == PATH_MAX) {
+ return -1;
+ }
+ return qemudOpenClientUNIX(path, 1);
+ } else {
+ return -1;
+ }
+ } else {
+ return qemudOpenClientAddr(uri->server, uri->port);
+ }
+}
+
+
+/*
+ * Open a connection to the QEMU manager
+ */
+int qemudOpen(virConnectPtr conn,
+ const char *name,
+ int flags){
+ xmlURIPtr uri;
+ int fd;
+
+ if (!name) {
+ return -1;
+ }
+
+ uri = xmlParseURI(name);
+ if (uri == NULL) {
+ if (!(flags & VIR_DRV_OPEN_QUIET))
+ qemudError(conn, NULL, VIR_ERR_NO_SUPPORT, name);
+ return(-1);
+ }
+
+ if (!uri->scheme ||
+ strcmp(uri->scheme, "qemud") ||
+ !uri->path) {
+ xmlFreeURI(uri);
+ return -1;
+ }
+
+ fd = qemudOpenConnection(uri, flags & VIR_DRV_OPEN_RO ? 1 : 0);
+ xmlFreeURI(uri);
+
+ if (fd < 0) {
+ return -1;
+ }
+
+ conn->handle = fd;
+
+ return 0;
+}
+
+
+int qemudClose (virConnectPtr conn) {
+ if (conn->handle != -1) {
+ close(conn->handle);
+ conn->handle = -1;
+ }
+ return 0;
+}
+
+
+int qemudGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED,
+ unsigned long *hvVer) {
+ struct qemud_packet req, reply;
+
+ req.header.type = QEMUD_PKT_GET_VERSION;
+ req.header.dataSize = 0;
+
+ if (qemudProcessRequest(conn, NULL, &req, &reply) < 0) {
+ return -1;
+ }
+
+ *hvVer = reply.data.getVersionReply.version;
+ return 0;
+}
+
+
+int qemudNodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virNodeInfoPtr info){
+ info->cores = 1;
+ info->threads = 1;
+ info->sockets = 1;
+ info->nodes = 1;
+ strcpy(info->model, "i686");
+ info->mhz = 6000;
+ info->cpus = 1;
+ info->memory = 1024*1024;
+ return 0;
+}
+
+
+int qemudNumOfDomains(virConnectPtr conn){
+ struct qemud_packet req, reply;
+
+ req.header.type = QEMUD_PKT_NUM_DOMAINS;
+ req.header.dataSize = 0;
+
+ if (qemudProcessRequest(conn, NULL, &req, &reply) < 0) {
+ return -1;
+ }
+
+ return reply.data.numDomainsReply.numDomains;
+}
+
+
+int qemudListDomains(virConnectPtr conn,
+ int *ids,
+ int maxids){
+ struct qemud_packet req, reply;
+
+ req.header.type = QEMUD_PKT_LIST_DOMAINS;
+ req.header.dataSize = 0;
+
+ if (qemudProcessRequest(conn, NULL, &req, &reply) < 0) {
+ return -1;
+ }
+
+ if (reply.data.listDomainsReply.numDomains > maxids)
+ return -1;
+
+ memmove(ids,
+ reply.data.listDomainsReply.domains,
+ sizeof(int)*reply.data.listDomainsReply.numDomains);
+
+ return reply.data.listDomainsReply.numDomains;
+}
+
+
+virDomainPtr
+qemudDomainCreateLinux(virConnectPtr conn, const char *xmlDesc,
+ unsigned int flags ATTRIBUTE_UNUSED){
+ struct qemud_packet req, reply;
+ virDomainPtr dom;
+ int len = strlen(xmlDesc);
+
+ if (len > (QEMUD_MAX_XML_LEN-1)) {
+ return NULL;
+ }
+
+ req.header.type = QEMUD_PKT_DOMAIN_CREATE;
+ req.header.dataSize = sizeof(req.data.domainCreateRequest);
+ strcpy(req.data.domainCreateRequest.xml, xmlDesc);
+ req.data.domainCreateRequest.xml[QEMUD_MAX_XML_LEN-1] = '\0';
+
+ if (qemudProcessRequest(conn, NULL, &req, &reply) < 0) {
+ return NULL;
+ }
+
+ reply.data.domainCreateReply.name[QEMUD_MAX_NAME_LEN-1] = '\0';
+
+ if (!(dom = virGetDomain(conn,
+ reply.data.domainCreateReply.name,
+ reply.data.domainCreateReply.uuid)))
+ return NULL;
+
+ dom->handle = reply.data.domainCreateReply.id;
+ return dom;
+}
+
+
+virDomainPtr qemudLookupDomainByID(virConnectPtr conn,
+ int id){
+ struct qemud_packet req, reply;
+ virDomainPtr dom;
+
+ req.header.type = QEMUD_PKT_DOMAIN_LOOKUP_BY_ID;
+ req.header.dataSize = sizeof(req.data.domainLookupByIDRequest);
+ req.data.domainLookupByIDRequest.id = id;
+
+ if (qemudProcessRequest(conn, NULL, &req, &reply) < 0) {
+ return NULL;
+ }
+
+ reply.data.domainLookupByIDReply.name[QEMUD_MAX_NAME_LEN-1] = '\0';
+
+ if (!(dom = virGetDomain(conn,
+ reply.data.domainLookupByIDReply.name,
+ reply.data.domainLookupByIDReply.uuid)))
+ return NULL;
+
+ dom->handle = id;
+ return dom;
+}
+
+
+virDomainPtr qemudLookupDomainByUUID(virConnectPtr conn,
+ const unsigned char *uuid){
+ struct qemud_packet req, reply;
+ virDomainPtr dom;
+
+ req.header.type = QEMUD_PKT_DOMAIN_LOOKUP_BY_UUID;
+ req.header.dataSize = sizeof(req.data.domainLookupByUUIDRequest);
+ memmove(req.data.domainLookupByUUIDRequest.uuid, uuid, QEMUD_UUID_RAW_LEN);
+
+ if (qemudProcessRequest(conn, NULL, &req, &reply) < 0) {
+ return NULL;
+ }
+
+ reply.data.domainLookupByUUIDReply.name[QEMUD_MAX_NAME_LEN-1] = '\0';
+
+ if (!(dom = virGetDomain(conn,
+ reply.data.domainLookupByUUIDReply.name,
+ uuid)))
+ return NULL;
+
+ dom->handle = reply.data.domainLookupByUUIDReply.id;
+ return dom;
+}
+
+
+virDomainPtr qemudLookupDomainByName(virConnectPtr conn,
+ const char *name){
+ struct qemud_packet req, reply;
+ virDomainPtr dom;
+
+ if (strlen(name) > (QEMUD_MAX_NAME_LEN-1))
+ return NULL;
+
+ req.header.type = QEMUD_PKT_DOMAIN_LOOKUP_BY_NAME;
+ req.header.dataSize = sizeof(req.data.domainLookupByNameRequest);
+ strcpy(req.data.domainLookupByNameRequest.name, name);
+
+ if (qemudProcessRequest(conn, NULL, &req, &reply) < 0) {
+ return NULL;
+ }
+
+ if (!(dom = virGetDomain(conn,
+ name,
+ reply.data.domainLookupByNameReply.uuid)))
+ return NULL;
+
+ dom->handle = reply.data.domainLookupByNameReply.id;
+ return dom;
+}
+int qemudShutdownDomain(virDomainPtr domain){
+ return qemudDestroyDomain(domain);
+}
+int qemudDestroyDomain(virDomainPtr domain){
+ struct qemud_packet req, reply;
+
+ req.header.type = QEMUD_PKT_DOMAIN_DESTROY;
+ req.header.dataSize = sizeof(req.data.domainDestroyRequest);
+ req.data.domainDestroyRequest.id = domain->handle;
+
+ if (qemudProcessRequest(domain->conn, NULL, &req, &reply) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+int qemudResumeDomain(virDomainPtr domain ATTRIBUTE_UNUSED){
+ return -1;
+}
+int qemudPauseDomain(virDomainPtr domain ATTRIBUTE_UNUSED){
+ return -1;
+}
+int qemudGetDomainInfo(virDomainPtr domain,
+ virDomainInfoPtr info){
+ struct qemud_packet req, reply;
+
+ req.header.type = QEMUD_PKT_DOMAIN_GET_INFO;
+ req.header.dataSize = sizeof(req.data.domainGetInfoRequest);
+ memmove(req.data.domainGetInfoRequest.uuid, domain->uuid, QEMUD_UUID_RAW_LEN);
+
+ if (qemudProcessRequest(domain->conn, NULL, &req, &reply) < 0) {
+ return -1;
+ }
+
+ memset(info, 0, sizeof(virDomainInfo));
+ switch (reply.data.domainGetInfoReply.runstate) {
+ case QEMUD_STATE_RUNNING:
+ info->state = VIR_DOMAIN_RUNNING;
+ break;
+
+ case QEMUD_STATE_PAUSED:
+ info->state = VIR_DOMAIN_PAUSED;
+ break;
+
+ case QEMUD_STATE_STOPPED:
+ info->state = VIR_DOMAIN_SHUTOFF;
+ break;
+
+ default:
+ return -1;
+ }
+ info->maxMem = reply.data.domainGetInfoReply.memory;
+ info->memory = reply.data.domainGetInfoReply.memory;
+ info->nrVirtCpu = reply.data.domainGetInfoReply.nrVirtCpu;
+ info->cpuTime = reply.data.domainGetInfoReply.cpuTime;
+
+ return 0;
+}
+char * qemudDomainDumpXML(virDomainPtr domain, int flags ATTRIBUTE_UNUSED){
+ struct qemud_packet req, reply;
+
+ req.header.type = QEMUD_PKT_DUMP_XML;
+ req.header.dataSize = sizeof(req.data.domainDumpXMLRequest);
+ memmove(req.data.domainDumpXMLRequest.uuid, domain->uuid, QEMUD_UUID_RAW_LEN);
+
+ if (qemudProcessRequest(domain->conn, NULL, &req, &reply) < 0) {
+ return NULL;
+ }
+
+ reply.data.domainDumpXMLReply.xml[QEMUD_MAX_XML_LEN-1] = '\0';
+
+ return strdup(reply.data.domainDumpXMLReply.xml);
+}
+
+int qemudSaveDomain(virDomainPtr domain ATTRIBUTE_UNUSED, const char *file ATTRIBUTE_UNUSED){
+ return -1;
+}
+int qemudRestoreDomain(virConnectPtr conn ATTRIBUTE_UNUSED, const char *file ATTRIBUTE_UNUSED){
+ return -1;
+}
+int qemudNumOfDefinedDomains(virConnectPtr conn){
+ struct qemud_packet req, reply;
+
+ req.header.type = QEMUD_PKT_NUM_DEFINED_DOMAINS;
+ req.header.dataSize = 0;
+
+ if (qemudProcessRequest(conn, NULL, &req, &reply) < 0) {
+ return -1;
+ }
+
+ return reply.data.numDefinedDomainsReply.numDomains;
+}
+
+int qemudListDefinedDomains(virConnectPtr conn,
+ const char **names,
+ int maxnames){
+ struct qemud_packet req, reply;
+ int i;
+
+ req.header.type = QEMUD_PKT_LIST_DEFINED_DOMAINS;
+ req.header.dataSize = 0;
+
+ if (qemudProcessRequest(conn, NULL, &req, &reply) < 0) {
+ return -1;
+ }
+
+ if (reply.data.listDefinedDomainsReply.numDomains > maxnames)
+ return -1;
+
+ for (i = 0 ; i < reply.data.listDefinedDomainsReply.numDomains ; i++) {
+ reply.data.listDefinedDomainsReply.domains[i][QEMUD_MAX_NAME_LEN-1] = '\0';
+ names[i] = strdup(reply.data.listDefinedDomainsReply.domains[i]);
+ }
+
+ return reply.data.listDefinedDomainsReply.numDomains;
+}
+int qemudDomainCreate(virDomainPtr dom) {
+ struct qemud_packet req, reply;
+
+ req.header.type = QEMUD_PKT_DOMAIN_START;
+ req.header.dataSize = sizeof(req.data.domainStartRequest);
+ memcpy(req.data.domainStartRequest.uuid, dom->uuid, QEMUD_UUID_RAW_LEN);
+
+ if (qemudProcessRequest(dom->conn, NULL, &req, &reply) < 0) {
+ return -1;
+ }
+
+ dom->handle = reply.data.domainStartReply.id;
+
+ return 0;
+}
+
+virDomainPtr qemudDomainDefineXML(virConnectPtr conn, const char *xml) {
+ struct qemud_packet req, reply;
+ virDomainPtr dom;
+ int len = strlen(xml);
+
+ if (len > (QEMUD_MAX_XML_LEN-1)) {
+ return NULL;
+ }
+
+ req.header.type = QEMUD_PKT_DOMAIN_DEFINE;
+ req.header.dataSize = sizeof(req.data.domainDefineRequest);
+ strcpy(req.data.domainDefineRequest.xml, xml);
+ req.data.domainDefineRequest.xml[QEMUD_MAX_XML_LEN-1] = '\0';
+
+ if (qemudProcessRequest(conn, NULL, &req, &reply) < 0) {
+ return NULL;
+ }
+
+ reply.data.domainDefineReply.name[QEMUD_MAX_NAME_LEN-1] = '\0';
+
+ if (!(dom = virGetDomain(conn,
+ reply.data.domainDefineReply.name,
+ reply.data.domainDefineReply.uuid)))
+ return NULL;
+
+ dom->handle = -1;
+ return dom;
+}
+
+int qemudUndefine(virDomainPtr dom) {
+ struct qemud_packet req, reply;
+ int ret = 0;
+
+ req.header.type = QEMUD_PKT_DOMAIN_UNDEFINE;
+ req.header.dataSize = sizeof(req.data.domainUndefineRequest);
+ memcpy(req.data.domainUndefineRequest.uuid, dom->uuid, QEMUD_UUID_RAW_LEN);
+
+ if (qemudProcessRequest(dom->conn, NULL, &req, &reply) < 0) {
+ ret = -1;
+ goto cleanup;
+ }
+
+ cleanup:
+ if (virFreeDomain(dom->conn, dom) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
Index: src/qemud_internal.h
===================================================================
RCS file: src/qemud_internal.h
diff -N src/qemud_internal.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/qemud_internal.h 5 Jan 2007 21:09:07 -0000
@@ -0,0 +1,48 @@
+/*
+ * qemud_internal.h: A backend for managing QEMU machines
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange at redhat.com>
+ */
+
+#ifndef __VIR_QEMUD_INTERNAL_H__
+#define __VIR_QEMUD_INTERNAL_H__
+
+#include <libvirt/virterror.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ void qemudRegister(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __VIR_QEMUD_INTERNAL_H__ */
+
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
Index: src/virsh.c
===================================================================
RCS file: /data/cvs/libvirt/src/virsh.c,v
retrieving revision 1.41
diff -u -p -r1.41 virsh.c
--- src/virsh.c 22 Nov 2006 17:48:29 -0000 1.41
+++ src/virsh.c 5 Jan 2007 21:09:08 -0000
@@ -292,7 +292,7 @@ cmdConnect(vshControl * ctl, vshCmd * cm
if (ctl->name)
free(ctl->name);
- ctl->name = vshCommandOptString(cmd, "name", NULL);
+ ctl->name = vshStrdup(ctl, vshCommandOptString(cmd, "name", NULL));
if (!ro)
ctl->conn = virConnectOpen(ctl->name);
@@ -2372,7 +2372,9 @@ vshInit(vshControl * ctl)
/* basic connection to hypervisor, for Xen connections unless
we're root open a read only connections. Allow 'test' HV
to be RW all the time though */
- if (ctl->uid == 0 || (ctl->name && !strncmp(ctl->name, "test", 4)))
+ if (ctl->uid == 0 || (ctl->name &&
+ (!strncmp(ctl->name, "test", 4) ||
+ !strncmp(ctl->name, "qemu", 4))))
ctl->conn = virConnectOpen(ctl->name);
else
ctl->conn = virConnectOpenReadOnly(ctl->name);
Index: src/virterror.c
===================================================================
RCS file: /data/cvs/libvirt/src/virterror.c,v
retrieving revision 1.19
diff -u -p -r1.19 virterror.c
--- src/virterror.c 8 Nov 2006 16:55:20 -0000 1.19
+++ src/virterror.c 5 Jan 2007 21:09:08 -0000
@@ -268,6 +268,9 @@ virDefaultErrorFunc(virErrorPtr err)
case VIR_FROM_RPC:
dom = "XML-RPC ";
break;
+ case VIR_FROM_QEMUD:
+ dom = "QEMUD ";
+ break;
}
if ((err->dom != NULL) && (err->code != VIR_ERR_INVALID_DOMAIN)) {
domain = err->dom->name;
More information about the libvir-list
mailing list