diff --git a/docs/uri.html.in b/docs/uri.html.in index e6326b2307..79f878678c 100644 --- a/docs/uri.html.in +++ b/docs/uri.html.in @@ -2,6 +2,8 @@
Since libvirt supports many different kinds of virtualization (often referred to as "drivers" or "hypervisors"), we need a @@ -13,41 +15,46 @@ machine over the network. To this end, libvirt uses URIs as used on the Web and as defined in RFC 2396. This page documents libvirt URIs.
-
The URI is passed as the name
parameter to virConnectOpen
or virConnectOpenReadOnly
. For example:
virConnectPtr conn = virConnectOpenReadOnly ("test:///default");-
+To simplify life for administrators, it is possible to setup URI aliases in a
+libvirt client configuration file. The configuration file is /etc/libvirt/libvirt.conf
+for the root user, or $HOME/.libvirt/libvirt.conf
for any unprivileged user.
+In this file, the following syntax can be used to setup aliases
+
+uri_aliases = [ + "hail=qemu+ssh://root@hail.cloud.example.com/system", + "sleet=qemu+ssh://root@sleet.cloud.example.com/system", +] ++ +
+ A URI alias should be a string made up from the characters
+ a-Z, 0-9, _, -
. Following the =
+ can be any libvirt URI string, including arbitrary URI parameters.
+ URI aliases will apply to any application opening a libvirt
+ connection, unless it has explicitly passed the VIR_CONNECT_NO_ALIASES
+ parameter to virConnectOpenAuth
. If the passed in
+ URI contains characters outside the allowed alias character
+ set, no alias lookup will be attempted.
+
In virsh use the -c
or --connect
option:
--connect=
URI option:
virt-install --connect=test:///default [other options]-
This section describes a feature which is new in libvirt >
0.2.3. For libvirt ≤ 0.2.3 use "xen"
.
@@ -87,9 +94,9 @@ virt-install --connect=test:///default [other options]
To access a Xen hypervisor running on the local machine
use the URI xen:///
.
To use QEMU support in libvirt you must be running the
libvirtd
daemon (named libvirt_qemud
@@ -119,9 +126,9 @@ KVM URIs are identical. You select between qemu, qemu accelerated and
KVM guests in the guest XML as described
here.
Remote URIs are formed by taking ordinary local URIs and adding a hostname and/or transport name. As a special case, using a URI @@ -182,9 +189,9 @@ We refer you to the libvirt remote URI reference and full documentation for libvirt remote support.
-The test driver is a dummy hypervisor for test purposes. The URIs supported are: @@ -196,12 +203,12 @@ host definitions built into the driver. a set of host definitions held in the named file. -
Libvirt allows you to pass a NULL
pointer to
virConnectOpen*
. Empty string (""
) acts in
@@ -223,9 +230,9 @@ the user to type a URI in directly (if that is appropriate). If your
application wishes to connect specifically to a Xen hypervisor, then
for future proofing it should choose a full xen:///
URI.
If XenD is running and configured in /etc/xen/xend-config.sxp
:
virsh -c ///var/run/xend/xend-socket-
http://...
(xend-http-server)
-
If XenD is running and configured in /etc/xen/xend-config.sxp
:
@@ -276,17 +283,17 @@ Notes:
libvirt, only the old-style sexpr interface known in the Xen
documentation as "unix server" or "http server".
-
"xen"
-
Another legacy URI is to specify name as the string
"xen"
. This will continue to refer to the Xen
hypervisor. However you should prefer a full xen:///
URI in all future code.
Libvirt continues to support connections to a separately running Xen proxy daemon. This provides a way to allow non-root users to make a diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 5f6a07a4dc..361881a018 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -844,7 +844,8 @@ typedef virNodeMemoryStats *virNodeMemoryStatsPtr; * Flags when opening a connection to a hypervisor */ typedef enum { - VIR_CONNECT_RO = 1, /* A readonly connection */ + VIR_CONNECT_RO = (1 << 0), /* A readonly connection */ + VIR_CONNECT_NO_ALIASES = (1 << 1), /* Don't try to resolve URI aliases */ } virConnectFlags; diff --git a/libvirt.spec.in b/libvirt.spec.in index 03bd7c72e8..262cfed044 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -1084,6 +1084,7 @@ rm -f $RPM_BUILD_ROOT%{_sysconfdir}/sysctl.d/libvirtd %defattr(-, root, root) %doc AUTHORS ChangeLog.gz NEWS README COPYING.LIB TODO +%config(noreplace) %{_sysconfdir}/libvirt/libvirt.conf %{_mandir}/man1/virsh.1* %{_mandir}/man1/virt-xml-validate.1* %{_mandir}/man1/virt-pki-validate.1* diff --git a/mingw32-libvirt.spec.in b/mingw32-libvirt.spec.in index 521790ce9b..c2690f34dc 100644 --- a/mingw32-libvirt.spec.in +++ b/mingw32-libvirt.spec.in @@ -110,7 +110,7 @@ rm -rf $RPM_BUILD_ROOT make DESTDIR=$RPM_BUILD_ROOT install -rm -rf $RPM_BUILD_ROOT%{_mingw32_sysconfdir}/libvirt +rm -rf $RPM_BUILD_ROOT%{_mingw32_sysconfdir}/libvirt/nwfilter rm -rf $RPM_BUILD_ROOT%{_mingw32_datadir}/doc/* rm -rf $RPM_BUILD_ROOT%{_mingw32_datadir}/gtk-doc/* @@ -126,6 +126,8 @@ rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) +%config(noreplace) %{_mingw32_sysconfdir}/libvirt/libvirt.conf + %{_mingw32_bindir}/libvirt-0.dll %{_mingw32_bindir}/virsh.exe %{_mingw32_bindir}/virt-xml-validate diff --git a/src/Makefile.am b/src/Makefile.am index 87d91ede79..07f27d2522 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -39,7 +39,7 @@ moddir = $(libdir)/libvirt/connection-driver mod_LTLIBRARIES = confdir = $(sysconfdir)/libvirt -conf_DATA = +conf_DATA = libvirt.conf augeasdir = $(datadir)/augeas/lenses augeas_DATA = diff --git a/src/libvirt.c b/src/libvirt.c index 69cffc5431..0b975daecc 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -40,6 +40,7 @@ #include "memory.h" #include "configmake.h" #include "intprops.h" +#include "conf.h" #include "rpc/virnettlscontext.h" #ifndef WITH_DRIVER_MODULES @@ -968,6 +969,126 @@ error: return -1; } +static char * +virConnectConfigFile(void) +{ + char *path; + if (geteuid() == 0) { + if (virAsprintf(&path, "%s/libvirt/libvirt.conf", + SYSCONFDIR) < 0) + goto no_memory; + } else { + char *userdir = virGetUserDirectory(geteuid()); + if (!userdir) + goto error; + + if (virAsprintf(&path, "%s/.libvirt/libvirt.conf", + userdir) < 0) + goto no_memory; + } + + return path; + +no_memory: + virReportOOMError(); +error: + return NULL; +} + +#define URI_ALIAS_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-" + +static int +virConnectOpenFindURIAliasMatch(virConfValuePtr value, const char *alias, char **uri) +{ + virConfValuePtr entry; + if (value->type != VIR_CONF_LIST) { + virLibConnError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Expected a list for 'uri_aliases' config parameter")); + return -1; + } + + entry = value->list; + while (entry) { + char *offset; + size_t safe; + + if (entry->type != VIR_CONF_STRING) { + virLibConnError(VIR_ERR_CONF_SYNTAX, "%s", + _("Expected a string for 'uri_aliases' config parameter list entry")); + return -1; + } + + if (!(offset = strchr(entry->str, '='))) { + virLibConnError(VIR_ERR_CONF_SYNTAX, + _("Malformed 'uri_aliases' config entry '%s', expected 'alias=uri://host/path'"), + entry->str); + return -1; + } + + safe = strspn(entry->str, URI_ALIAS_CHARS); + if (safe < (offset - entry->str)) { + virLibConnError(VIR_ERR_CONF_SYNTAX, + _("Malformed 'uri_aliases' config entry '%s', aliases may only container 'a-Z, 0-9, _, -'"), + entry->str); + return -1; + } + + if (STREQLEN(entry->str, alias, offset-entry->str)) { + VIR_DEBUG("Resolved alias '%s' to '%s'", + alias, offset+1); + if (!(*uri = strdup(offset+1))) { + virReportOOMError(); + return -1; + } + return 0; + } + + entry = entry->next; + } + + VIR_DEBUG("No alias found for '%s', passing through to drivers", + alias); + return 0; +} + +static int +virConnectOpenResolveURIAlias(const char *alias, char **uri) +{ + char *config = NULL; + int ret = -1; + virConfPtr conf = NULL; + virConfValuePtr value = NULL; + + *uri = NULL; + + /* Short circuit to avoid doing URI alias resolution + * when it clearly isn't an valid alias */ + if (strspn(alias, URI_ALIAS_CHARS) != strlen(alias)) + return 0; + + if (!(config = virConnectConfigFile())) + goto cleanup; + + if (!virFileExists(config)) { + ret = 0; + goto cleanup; + } + + VIR_DEBUG("Loading config file '%s'", config); + if (!(conf = virConfReadFile(config, 0))) + goto cleanup; + + if ((value = virConfGetValue(conf, "uri_aliases"))) + ret = virConnectOpenFindURIAliasMatch(value, alias, uri); + else + ret = 0; + +cleanup: + virConfFree(conf); + VIR_FREE(config); + return ret; +} + static virConnectPtr do_open (const char *name, virConnectAuthPtr auth, @@ -998,6 +1119,7 @@ do_open (const char *name, } if (name) { + char *alias = NULL; /* Convert xen -> xen:/// for back compat */ if (STRCASEEQ(name, "xen")) name = "xen:///"; @@ -1008,26 +1130,34 @@ do_open (const char *name, if (STREQ (name, "xen://")) name = "xen:///"; - ret->uri = xmlParseURI (name); + if (!(flags & VIR_CONNECT_NO_ALIASES) && + virConnectOpenResolveURIAlias(name, &alias) < 0) + goto failed; + + ret->uri = xmlParseURI (alias ? alias : name); if (!ret->uri) { virLibConnError(VIR_ERR_INVALID_ARG, - _("could not parse connection URI")); + _("could not parse connection URI %s"), + alias ? alias : name); + VIR_FREE(alias); goto failed; } VIR_DEBUG("name \"%s\" to URI components:\n" - " scheme %s\n" - " opaque %s\n" - " authority %s\n" - " server %s\n" - " user %s\n" - " port %d\n" - " path %s\n", - name, - NULLSTR(ret->uri->scheme), NULLSTR(ret->uri->opaque), - NULLSTR(ret->uri->authority), NULLSTR(ret->uri->server), - NULLSTR(ret->uri->user), ret->uri->port, - NULLSTR(ret->uri->path)); + " scheme %s\n" + " opaque %s\n" + " authority %s\n" + " server %s\n" + " user %s\n" + " port %d\n" + " path %s\n", + alias ? alias : name, + NULLSTR(ret->uri->scheme), NULLSTR(ret->uri->opaque), + NULLSTR(ret->uri->authority), NULLSTR(ret->uri->server), + NULLSTR(ret->uri->user), ret->uri->port, + NULLSTR(ret->uri->path)); + + VIR_FREE(alias); } else { VIR_DEBUG("no name, allowing driver auto-select"); } diff --git a/src/libvirt.conf b/src/libvirt.conf new file mode 100644 index 0000000000..c54903ce1c --- /dev/null +++ b/src/libvirt.conf @@ -0,0 +1,12 @@ +# +# This can be used to setup URI aliases for frequently +# used connection URIs. Aliases may contain only the +# characters a-Z, 0-9, _, -. +# +# Following the '=' may be any valid libvirt connection +# URI, including arbitrary parameters + +#uri_aliases = [ +# "hail=qemu+ssh://root@hail.cloud.example.com/system", +# "sleet=qemu+ssh://root@sleet.cloud.example.com/system", +#] diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 4dc6974550..1dea327fb5 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -313,6 +313,11 @@ doRemoteOpen (virConnectPtr conn, if (conn->uri) { if (!conn->uri->scheme) { /* This is the ///var/lib/xen/xend-socket local path style */ + if (!conn->uri->path) + return VIR_DRV_OPEN_DECLINED; + if (conn->uri->path[0] != '/') + return VIR_DRV_OPEN_DECLINED; + transport = trans_unix; } else { transport_str = get_transport_from_scheme (conn->uri->scheme); diff --git a/src/util/conf.c b/src/util/conf.c index 00045b54b4..c8dcc7f953 100644 --- a/src/util/conf.c +++ b/src/util/conf.c @@ -808,10 +808,8 @@ int virConfFree(virConfPtr conf) { virConfEntryPtr tmp; - if (conf == NULL) { - virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); - return(-1); - } + if (conf == NULL) + return 0; tmp = conf->entries; while (tmp) { diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index 68abb1759a..b3e7782890 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -296,17 +296,7 @@ xenUnifiedOpen (virConnectPtr conn, virConnectAuthPtr auth, unsigned int flags) 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(VIR_ERR_INTERNAL_ERROR, - _("unexpected Xen URI path '%s', try ///var/lib/xen/xend-socket"), - NULLSTR(conn->uri->path)); - return VIR_DRV_OPEN_ERROR; - } + return VIR_DRV_OPEN_DECLINED; } }