+Thu Jun 12 13:06:42 BST 2009 Daniel P. Berrange <berrange@redhat.com>
+
+ Improve error reporting for virConnecOpen URIs
+ * src/lxc_driver.c, src/openvz_driver.c, src/qemu_driver.c,
+ src/uml_driver.c, src/xen_unified.c: Always return ACCEPT
+ or ERROR for URIs without hostname set, but with the driver's
+ matching URI scheme. ie never decline a correct URI
+ * src/xend_internal.c: Default port to 8000 if not given
+ in the http:// URI.
+ * src/remote_internal.c: Accept all URIs not handled by an
+ earlier driver.
+ * src/virterror.c: Improve error message text for
+ VIR_ERR_NO_CONNECT code
+
Thu Jun 12 12:26:42 BST 2009 Daniel P. Berrange <berrange@redhat.com>
Fix re-detection of transient VMs after libvirtd restart
}
-static int lxcProbe(void)
-{
- if (getuid() != 0 ||
- lxcContainerAvailable(0) < 0)
- return 0;
-
- return 1;
-}
-
static virDrvOpenStatus lxcOpen(virConnectPtr conn,
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
int flags ATTRIBUTE_UNUSED)
{
- if (lxc_driver == NULL)
- goto declineConnection;
-
/* Verify uri was specified */
if (conn->uri == NULL) {
- if (!lxcProbe())
- goto declineConnection;
+ if (lxc_driver == NULL)
+ return VIR_DRV_OPEN_DECLINED;
conn->uri = xmlParseURI("lxc:///");
if (!conn->uri) {
virReportOOMError(conn);
return VIR_DRV_OPEN_ERROR;
}
- } else if (conn->uri->scheme == NULL ||
- STRNEQ(conn->uri->scheme, "lxc")) {
- goto declineConnection;
- } else if (!lxcProbe()) {
- goto declineConnection;
- }
+ } else {
+ if (conn->uri->scheme == NULL ||
+ STRNEQ(conn->uri->scheme, "lxc"))
+ return VIR_DRV_OPEN_DECLINED;
+ /* Leave for remote driver */
+ if (conn->uri->server != NULL)
+ return VIR_DRV_OPEN_DECLINED;
+
+ /* If path isn't '/' then they typoed, tell them correct path */
+ if (STRNEQ(conn->uri->path, "/")) {
+ lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected LXC URI path '%s', try lxc:///"),
+ conn->uri->path);
+ return VIR_DRV_OPEN_ERROR;
+ }
+
+ /* URI was good, but driver isn't active */
+ if (lxc_driver == NULL) {
+ lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("lxc state driver is not active"));
+ return VIR_DRV_OPEN_ERROR;
+ }
+ }
conn->privateData = lxc_driver;
return VIR_DRV_OPEN_SUCCESS;
-
-declineConnection:
- return VIR_DRV_OPEN_DECLINED;
}
static int lxcClose(virConnectPtr conn)
return ret;
}
-static int openvzProbe(void)
-{
- if (geteuid() == 0 &&
- virFileExists("/proc/vz"))
- return 1;
-
- return 0;
-}
-
static virDrvOpenStatus openvzOpen(virConnectPtr conn,
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
int flags ATTRIBUTE_UNUSED)
{
struct openvz_driver *driver;
- if (!openvzProbe())
- return VIR_DRV_OPEN_DECLINED;
if (conn->uri == NULL) {
+ if (!virFileExists("/proc/vz"))
+ return VIR_DRV_OPEN_DECLINED;
+
+ if (access("/proc/vz", W_OK) < 0)
+ return VIR_DRV_OPEN_DECLINED;
+
conn->uri = xmlParseURI("openvz:///system");
if (conn->uri == NULL) {
- openvzError(conn, VIR_ERR_NO_DOMAIN, NULL);
+ virReportOOMError(conn);
+ return VIR_DRV_OPEN_ERROR;
+ }
+ } else {
+ /* If scheme isn't 'openvz', then its for another driver */
+ if (conn->uri->scheme == NULL ||
+ STRNEQ (conn->uri->scheme, "openvz"))
+ return VIR_DRV_OPEN_DECLINED;
+
+ /* If server name is given, its for remote driver */
+ if (conn->uri->server != NULL)
+ return VIR_DRV_OPEN_DECLINED;
+
+ /* If path isn't /system, then they typoed, so tell them correct path */
+ if (conn->uri->path == NULL ||
+ STRNEQ (conn->uri->path, "/system")) {
+ openvzError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected OpenVZ URI path '%s', try openvz:///system"),
+ conn->uri->path);
+ return VIR_DRV_OPEN_ERROR;
+ }
+
+ if (!virFileExists("/proc/vz")) {
+ openvzError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
+ _("OpenVZ control file /proc/vz does not exist"));
+ return VIR_DRV_OPEN_ERROR;
+ }
+
+ if (access("/proc/vz", W_OK) < 0) {
+ openvzError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
+ _("OpenVZ control file /proc/vz is not accessible"));
return VIR_DRV_OPEN_ERROR;
}
- } else if (conn->uri->scheme == NULL ||
- conn->uri->path == NULL ||
- STRNEQ (conn->uri->scheme, "openvz") ||
- STRNEQ (conn->uri->path, "/system")) {
- return VIR_DRV_OPEN_DECLINED;
}
+ /* We now know the URI is definitely for this driver, so beyond
+ * here, don't return DECLINED, always use ERROR */
+
if (VIR_ALLOC(driver) < 0) {
virReportOOMError(conn);
return VIR_DRV_OPEN_ERROR;
}
-/**
- * qemudProbe:
- *
- * Probe for the availability of the qemu driver, assume the
- * presence of QEmu emulation if the binaries are installed
- */
-static int qemudProbe(void)
-{
- if ((virFileExists("/usr/bin/qemu")) ||
- (virFileExists("/usr/bin/qemu-kvm")) ||
- (virFileExists("/usr/bin/kvm")) ||
- (virFileExists("/usr/bin/xenner")))
- return 1;
-
- return 0;
-}
static virDrvOpenStatus qemudOpen(virConnectPtr conn,
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
int flags ATTRIBUTE_UNUSED) {
uid_t uid = getuid();
- if (qemu_driver == NULL)
- goto decline;
-
- if (!qemudProbe())
- goto decline;
-
if (conn->uri == NULL) {
- conn->uri = xmlParseURI(uid ? "qemu:///session" : "qemu:///system");
+ if (qemu_driver == NULL)
+ return VIR_DRV_OPEN_DECLINED;
+
+ conn->uri = xmlParseURI(uid == 0 ?
+ "qemu:///system" :
+ "qemu:///session");
if (!conn->uri) {
virReportOOMError(conn);
return VIR_DRV_OPEN_ERROR;
}
- } else if (conn->uri->scheme == NULL ||
- conn->uri->path == NULL)
- goto decline;
+ } else {
+ /* If URI isn't 'qemu' its definitely not for us */
+ if (conn->uri->scheme == NULL ||
+ STRNEQ(conn->uri->scheme, "qemu"))
+ return VIR_DRV_OPEN_DECLINED;
+
+ /* Allow remote driver to deal with URIs with hostname server */
+ if (conn->uri->server != NULL)
+ return VIR_DRV_OPEN_DECLINED;
+
+ if (!uid) {
+ if (STRNEQ (conn->uri->path, "/system") &&
+ STRNEQ (conn->uri->path, "/session")) {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected QEMU URI path '%s', try qemu:///system"),
+ conn->uri->path);
+ return VIR_DRV_OPEN_ERROR;
+ }
+ } else {
+ if (STRNEQ (conn->uri->path, "/session")) {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected QEMU URI path '%s', try qemu:///session"),
+ conn->uri->path);
+ return VIR_DRV_OPEN_ERROR;
+ }
+ }
- if (STRNEQ (conn->uri->scheme, "qemu"))
- goto decline;
+ /* URI was good, but driver isn't active */
+ if (qemu_driver == NULL) {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
+ _("qemu state driver is not active"));
+ return VIR_DRV_OPEN_ERROR;
+ }
- if (uid != 0) {
- if (STRNEQ (conn->uri->path, "/session"))
- goto decline;
- } else { /* root */
- if (STRNEQ (conn->uri->path, "/system") &&
- STRNEQ (conn->uri->path, "/session"))
- goto decline;
}
-
conn->privateData = qemu_driver;
return VIR_DRV_OPEN_SUCCESS;
-
- decline:
- return VIR_DRV_OPEN_DECLINED;
}
static int qemudClose(virConnectPtr conn) {
enum virDrvOpenRemoteFlags {
VIR_DRV_OPEN_REMOTE_RO = (1 << 0),
- VIR_DRV_OPEN_REMOTE_UNIX = (1 << 1),
- VIR_DRV_OPEN_REMOTE_USER = (1 << 2),
- VIR_DRV_OPEN_REMOTE_AUTOSTART = (1 << 3),
+ VIR_DRV_OPEN_REMOTE_USER = (1 << 1), /* Use the per-user socket path */
+ VIR_DRV_OPEN_REMOTE_AUTOSTART = (1 << 2), /* Autostart a per-user daemon */
};
-/* What transport? */
-enum {
- trans_tls,
- trans_unix,
- trans_ssh,
- trans_ext,
- trans_tcp,
-} transport;
-
+/*
+ * URIs that this driver needs to handle:
+ *
+ * The easy answer:
+ * - Everything that no one else has yet claimed, but nothing if
+ * we're inside the libvirtd daemon
+ *
+ * The hard answer:
+ * - Plain paths (///var/lib/xen/xend-socket) -> UNIX domain socket
+ * - xxx://servername/ -> TLS connection
+ * - xxx+tls://servername/ -> TLS connection
+ * - xxx+tls:/// -> TLS connection to localhost
+ * - xxx+tcp://servername/ -> TCP connection
+ * - xxx+tcp:/// -> TCP connection to localhost
+ * - xxx+unix:/// -> UNIX domain socket
+ * - xxx:/// -> UNIX domain socket
+ */
static int
doRemoteOpen (virConnectPtr conn,
struct private_data *priv,
{
int wakeupFD[2] = { -1, -1 };
char *transport_str = NULL;
+ enum {
+ trans_tls,
+ trans_unix,
+ trans_ssh,
+ trans_ext,
+ trans_tcp,
+ } transport;
- if (conn->uri) {
- if (!conn->uri->scheme)
- return VIR_DRV_OPEN_DECLINED;
-
- transport_str = get_transport_from_scheme (conn->uri->scheme);
+ /* We handle *ALL* URIs here. The caller has rejected any
+ * URIs we don't care about */
- if (!transport_str || STRCASEEQ (transport_str, "tls"))
- transport = trans_tls;
- else if (STRCASEEQ (transport_str, "unix"))
+ if (conn->uri) {
+ if (!conn->uri->scheme) {
+ /* This is the ///var/lib/xen/xend-socket local path style */
transport = trans_unix;
- else if (STRCASEEQ (transport_str, "ssh"))
- transport = trans_ssh;
- else if (STRCASEEQ (transport_str, "ext"))
- transport = trans_ext;
- else if (STRCASEEQ (transport_str, "tcp"))
- transport = trans_tcp;
- else {
- error (conn, VIR_ERR_INVALID_ARG,
- _("remote_open: transport in URL not recognised "
- "(should be tls|unix|ssh|ext|tcp)"));
- return VIR_DRV_OPEN_ERROR;
- }
- }
+ } else {
+ transport_str = get_transport_from_scheme (conn->uri->scheme);
- if (!transport_str) {
- if ((!conn->uri || !conn->uri->server) &&
- (flags & VIR_DRV_OPEN_REMOTE_UNIX))
- transport = trans_unix;
- else
- return VIR_DRV_OPEN_DECLINED; /* Decline - not a remote URL. */
+ if (!transport_str) {
+ if (conn->uri->server)
+ transport = trans_tls;
+ else
+ transport = trans_unix;
+ } else {
+ if (STRCASEEQ (transport_str, "tls"))
+ transport = trans_tls;
+ else if (STRCASEEQ (transport_str, "unix"))
+ transport = trans_unix;
+ else if (STRCASEEQ (transport_str, "ssh"))
+ transport = trans_ssh;
+ else if (STRCASEEQ (transport_str, "ext"))
+ transport = trans_ext;
+ else if (STRCASEEQ (transport_str, "tcp"))
+ transport = trans_tcp;
+ else {
+ error (conn, VIR_ERR_INVALID_ARG,
+ _("remote_open: transport in URL not recognised "
+ "(should be tls|unix|ssh|ext|tcp)"));
+ return VIR_DRV_OPEN_ERROR;
+ }
+ }
+ }
+ } else {
+ /* No URI, then must be probing so use UNIX socket */
+ transport = trans_unix;
}
/* Local variables which we will initialise. These can
/* Construct the original name. */
if (!name) {
- if (STREQ(conn->uri->scheme, "remote") ||
- STRPREFIX(conn->uri->scheme, "remote+")) {
+ if (conn->uri->scheme &&
+ (STREQ(conn->uri->scheme, "remote") ||
+ STRPREFIX(conn->uri->scheme, "remote+"))) {
/* Allow remote serve to probe */
name = strdup("");
} else {
freeaddrinfo (res);
virReportSystemError(conn, saved_errno,
- _("unable to connect to '%s'"),
+ _("unable to connect to libvirtd at '%s'"),
priv->hostname);
goto failed;
if (flags & VIR_CONNECT_RO)
rflags |= VIR_DRV_OPEN_REMOTE_RO;
- rflags |= VIR_DRV_OPEN_REMOTE_UNIX;
ret = doRemoteOpen(conn, *priv, auth, rflags);
if (ret != VIR_DRV_OPEN_SUCCESS) {
if (flags & VIR_CONNECT_RO)
rflags |= VIR_DRV_OPEN_REMOTE_RO;
- /*
- * If no servername is given, and no +XXX
- * transport is listed, then force to a
- * local UNIX socket connection
- */
- if (conn->uri &&
- !conn->uri->server &&
- conn->uri->scheme &&
- !strchr(conn->uri->scheme, '+')) {
- DEBUG0("Auto-remote UNIX socket");
- rflags |= VIR_DRV_OPEN_REMOTE_UNIX;
- }
-
/*
* If no servername is given, and no +XXX
* transport is listed, or transport is unix,
*/
if (!conn->uri) {
DEBUG0("Auto-probe remote URI");
- rflags |= VIR_DRV_OPEN_REMOTE_UNIX;
#ifndef __sun
if (getuid() > 0) {
DEBUG0("Auto-spawn user daemon instance");
if (conn->uri->server)
return VIR_DRV_OPEN_DECLINED;
- if (conn->uri->server)
- return VIR_DRV_OPEN_DECLINED;
-
/* From this point on, the connection is for us. */
if (!conn->uri->path
|| conn->uri->path[0] == '\0'
int flags ATTRIBUTE_UNUSED) {
uid_t uid = getuid();
- if (uml_driver == NULL)
- goto decline;
+ if (conn->uri == NULL) {
+ if (uml_driver == NULL)
+ return VIR_DRV_OPEN_DECLINED;
- if (conn->uri != NULL) {
- if (conn->uri->scheme == NULL || conn->uri->path == NULL)
- goto decline;
+ conn->uri = xmlParseURI(uid == 0 ?
+ "uml:///system" :
+ "uml:///session");
+ if (!conn->uri) {
+ virReportOOMError(conn);
+ return VIR_DRV_OPEN_ERROR;
+ }
+ } else {
+ if (conn->uri->scheme == NULL ||
+ STRNEQ (conn->uri->scheme, "uml"))
+ return VIR_DRV_OPEN_DECLINED;
+
+ /* Allow remote driver to deal with URIs with hostname server */
+ if (conn->uri->server != NULL)
+ return VIR_DRV_OPEN_DECLINED;
- if (STRNEQ (conn->uri->scheme, "uml"))
- goto decline;
- if (uid != 0) {
- if (STRNEQ (conn->uri->path, "/session"))
- goto decline;
- } else { /* root */
+ /* Check path and tell them correct path if they made a mistake */
+ if (uid == 0) {
if (STRNEQ (conn->uri->path, "/system") &&
- STRNEQ (conn->uri->path, "/session"))
- goto decline;
+ STRNEQ (conn->uri->path, "/session")) {
+ umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected UML URI path '%s', try uml:///system"),
+ conn->uri->path);
+ return VIR_DRV_OPEN_ERROR;
+ }
+ } else {
+ if (STRNEQ (conn->uri->path, "/session")) {
+ umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected UML URI path '%s', try uml:///session"),
+ conn->uri->path);
+ return VIR_DRV_OPEN_ERROR;
+ }
}
- } else {
- conn->uri = xmlParseURI(uid ? "uml:///session" : "uml:///system");
- if (!conn->uri) {
- virReportOOMError(conn);
+
+ /* URI was good, but driver isn't active */
+ if (uml_driver == NULL) {
+ umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
+ _("uml state driver is not active"));
return VIR_DRV_OPEN_ERROR;
}
}
conn->privateData = uml_driver;
return VIR_DRV_OPEN_SUCCESS;
-
- decline:
- return VIR_DRV_OPEN_DECLINED;
}
static int umlClose(virConnectPtr conn) {
break;
case VIR_ERR_NO_CONNECT:
if (info == NULL)
- errmsg = _("could not connect to hypervisor");
+ errmsg = _("no hypervisor driver available");
else
- errmsg = _("could not connect to %s");
+ errmsg = _("no hypervisor driver available for %s");
break;
case VIR_ERR_INVALID_CONN:
if (info == NULL)
virReportOOMError (NULL);
return VIR_DRV_OPEN_ERROR;
}
- }
-
- /* Refuse any scheme which isn't "xen://" or "http://". */
- if (conn->uri->scheme &&
- STRCASENEQ(conn->uri->scheme, "xen") &&
- STRCASENEQ(conn->uri->scheme, "http"))
- return VIR_DRV_OPEN_DECLINED;
+ } else {
+ if (conn->uri->scheme) {
+ /* Decline any scheme which isn't "xen://" or "http://". */
+ if (STRCASENEQ(conn->uri->scheme, "xen") &&
+ STRCASENEQ(conn->uri->scheme, "http"))
+ return VIR_DRV_OPEN_DECLINED;
+
+
+ /* Return an error if the path isn't '' or '/' */
+ if (conn->uri->path &&
+ STRNEQ(conn->uri->path, "") &&
+ STRNEQ(conn->uri->path, "/")) {
+ xenUnifiedError(NULL, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected Xen URI path '%s', try xen:///"),
+ conn->uri->path);
+ return VIR_DRV_OPEN_ERROR;
+ }
- /* xmlParseURI will parse a naked string like "foo" as a URI with
- * a NULL scheme. That's not useful for us because we want to only
- * allow full pathnames (eg. ///var/lib/xen/xend-socket). Decline
- * anything else.
- */
- if (!conn->uri->scheme && (!conn->uri->path || conn->uri->path[0] != '/'))
- return VIR_DRV_OPEN_DECLINED;
+ /* Decline any xen:// URI with a server specified, allowing remote
+ * driver to handle, but keep any http:/// URIs */
+ if (STRCASEEQ(conn->uri->scheme, "xen") &&
+ conn->uri->server)
+ return VIR_DRV_OPEN_DECLINED;
+ } else {
+ /* Special case URI for Xen driver only:
+ *
+ * Treat a plain path as a Xen UNIX socket path, and give
+ * error unless path is absolute
+ */
+ if (!conn->uri->path || conn->uri->path[0] != '/') {
+ xenUnifiedError(NULL, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected Xen URI path '%s', try ///var/lib/xen/xend-socket"),
+ NULLSTR(conn->uri->path));
+ return VIR_DRV_OPEN_ERROR;
+ }
+ }
+ }
- /* Refuse any xen:// URI with a server specified - allow remote to do it */
- if (conn->uri->scheme && STRCASEEQ(conn->uri->scheme, "xen") && conn->uri->server)
- return VIR_DRV_OPEN_DECLINED;
+ /* We now know the URI is definitely for this driver, so beyond
+ * here, don't return DECLINED, always use ERROR */
/* Allocate per-connection private data. */
if (VIR_ALLOC(priv) < 0) {
xend_detect_config_version(conn) == -1)
goto failed;
} else if (STRCASEEQ (conn->uri->scheme, "http")) {
- if (virAsprintf(&port, "%d", conn->uri->port) == -1)
+ if (conn->uri->port &&
+ virAsprintf(&port, "%d", conn->uri->port) == -1)
goto failed;
- if (xenDaemonOpen_tcp(conn, conn->uri->server, port) < 0 ||
+ if (xenDaemonOpen_tcp(conn,
+ conn->uri->server ? conn->uri->server : "localhost",
+ port ? port : "8000") < 0 ||
xend_detect_config_version(conn) == -1)
goto failed;
} else {