mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-22 04:25:18 +00:00
Allow for URI aliases when connecting to libvirt
This adds support for a libvirt client configuration file either /etc/libvirt/libvirt.conf for privileged clients, or $HOME/.libvirt/libvirt.conf for unprivileged clients. It allows one parameter uri_aliases = [ "hail=qemu+ssh://root@hail.cloud.example.com/system", "sleet=qemu+ssh://root@sleet.cloud.example.com/system", ] Any call to virConnectOpen with a non-NULL URI will first attempt to match against the uri_aliases list. An application can disable this by using VIR_CONNECT_NO_ALIASES * docs/uri.html.in: Document URI aliases * include/libvirt/libvirt.h.in: Add VIR_CONNECT_NO_ALIASES * libvirt.spec.in, mingw32-libvirt.spec.in: Add /etc/libvirt/libvirt.conf * src/Makefile.am: Install default config file * src/libvirt.c: Add support for URI aliases * src/remote/remote_driver.c: Don't try to handle URIs with no scheme and which clearly are not paths * src/util/conf.c: Don't raise error on virConfFree(NULL) * src/xen/xen_driver.c: Don't raise error on URIs with no scheme
This commit is contained in:
parent
02e92dc470
commit
777ffbd0e2
103
docs/uri.html.in
103
docs/uri.html.in
@ -2,6 +2,8 @@
|
||||
<html>
|
||||
<body>
|
||||
<h1 >Connection URIs</h1>
|
||||
|
||||
<ul id="toc"></ul>
|
||||
<p>
|
||||
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 <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>. This page
|
||||
documents libvirt URIs.
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="#URI_libvirt">Specifying URIs to libvirt</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#URI_virsh">Specifying URIs to virsh, virt-manager and virt-install</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#URI_xen">xen:/// URI</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#URI_qemu">qemu:///... QEMU and KVM URIs</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#URI_remote">Remote URIs</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#URI_test">test:///... Test URIs</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#URI_legacy">Other & legacy URI formats</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>
|
||||
<a name="URI_libvirt">Specifying URIs to libvirt</a>
|
||||
</h3>
|
||||
<h2><a name="URI_libvirt">Specifying URIs to libvirt</a></h2>
|
||||
|
||||
<p>
|
||||
The URI is passed as the <code>name</code> parameter to <a href="html/libvirt-libvirt.html#virConnectOpen"><code>virConnectOpen</code></a> or <a href="html/libvirt-libvirt.html#virConnectOpenReadOnly"><code>virConnectOpenReadOnly</code></a>. For example:
|
||||
</p>
|
||||
<pre>
|
||||
virConnectPtr conn = virConnectOpenReadOnly (<b>"test:///default"</b>);
|
||||
</pre>
|
||||
<h3>
|
||||
<h2>
|
||||
<a name="URI_config">Configuring URI aliases</a>
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
To simplify life for administrators, it is possible to setup URI aliases in a
|
||||
libvirt client configuration file. The configuration file is <code>/etc/libvirt/libvirt.conf</code>
|
||||
for the root user, or <code>$HOME/.libvirt/libvirt.conf</code> for any unprivileged user.
|
||||
In this file, the following syntax can be used to setup aliases
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
uri_aliases = [
|
||||
"hail=qemu+ssh://root@hail.cloud.example.com/system",
|
||||
"sleet=qemu+ssh://root@sleet.cloud.example.com/system",
|
||||
]
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
A URI alias should be a string made up from the characters
|
||||
<code>a-Z, 0-9, _, -</code>. Following the <code>=</code>
|
||||
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 <code>VIR_CONNECT_NO_ALIASES</code>
|
||||
parameter to <code>virConnectOpenAuth</code>. If the passed in
|
||||
URI contains characters outside the allowed alias character
|
||||
set, no alias lookup will be attempted.
|
||||
</p>
|
||||
|
||||
<h2>
|
||||
<a name="URI_virsh">Specifying URIs to virsh, virt-manager and virt-install</a>
|
||||
</h3>
|
||||
</h2>
|
||||
<p>
|
||||
In virsh use the <code>-c</code> or <code>--connect</code> option:
|
||||
</p>
|
||||
@ -76,9 +83,9 @@ In virt-install use the <code>--connect=</code><i>URI</i> option:
|
||||
<pre>
|
||||
virt-install <b>--connect=test:///default</b> <i>[other options]</i>
|
||||
</pre>
|
||||
<h3>
|
||||
<h2>
|
||||
<a name="URI_xen">xen:/// URI</a>
|
||||
</h3>
|
||||
</h2>
|
||||
<p>
|
||||
<i>This section describes a feature which is new in libvirt >
|
||||
0.2.3. For libvirt ≤ 0.2.3 use <a href="#URI_legacy_xen"><code>"xen"</code></a>.</i>
|
||||
@ -87,9 +94,9 @@ virt-install <b>--connect=test:///default</b> <i>[other options]</i>
|
||||
To access a Xen hypervisor running on the local machine
|
||||
use the URI <code>xen:///</code>.
|
||||
</p>
|
||||
<h3>
|
||||
<h2>
|
||||
<a name="URI_qemu">qemu:///... QEMU and KVM URIs</a>
|
||||
</h3>
|
||||
</h2>
|
||||
<p>
|
||||
To use QEMU support in libvirt you must be running the
|
||||
<code>libvirtd</code> daemon (named <code>libvirt_qemud</code>
|
||||
@ -119,9 +126,9 @@ KVM URIs are identical. You select between qemu, qemu accelerated and
|
||||
KVM guests in the <a href="format.html#KVM1">guest XML as described
|
||||
here</a>.
|
||||
</p>
|
||||
<h3>
|
||||
<h2>
|
||||
<a name="URI_remote">Remote URIs</a>
|
||||
</h3>
|
||||
</h2>
|
||||
<p>
|
||||
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 <a href="remote.html#Remote_URI_reference">the libvirt
|
||||
remote URI reference</a> and <a href="remote.html">full documentation
|
||||
for libvirt remote support</a>.
|
||||
</p>
|
||||
<h3>
|
||||
<h2>
|
||||
<a name="URI_test">test:///... Test URIs</a>
|
||||
</h3>
|
||||
</h2>
|
||||
<p>
|
||||
The test driver is a dummy hypervisor for test purposes.
|
||||
The URIs supported are:
|
||||
@ -196,12 +203,12 @@ host definitions built into the driver. </li>
|
||||
a set of host definitions held in the named file.
|
||||
</li>
|
||||
</ul>
|
||||
<h3>
|
||||
<h2>
|
||||
<a name="URI_legacy">Other & legacy URI formats</a>
|
||||
</h3>
|
||||
<h4>
|
||||
</h2>
|
||||
<h3>
|
||||
<a name="URI_NULL">NULL and empty string URIs</a>
|
||||
</h4>
|
||||
</h3>
|
||||
<p>
|
||||
Libvirt allows you to pass a <code>NULL</code> pointer to
|
||||
<code>virConnectOpen*</code>. Empty string (<code>""</code>) 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 <a href="#URI_xen"><code>xen:///</code> URI</a>.
|
||||
</p>
|
||||
<h4>
|
||||
<h3>
|
||||
<a name="URI_file">File paths (xend-unix-server)</a>
|
||||
</h4>
|
||||
</h3>
|
||||
<p>
|
||||
If XenD is running and configured in <code>/etc/xen/xend-config.sxp</code>:
|
||||
</p>
|
||||
@ -240,9 +247,9 @@ using a file URI such as:
|
||||
<pre>
|
||||
virsh -c ///var/run/xend/xend-socket
|
||||
</pre>
|
||||
<h4>
|
||||
<h3>
|
||||
<a name="URI_http">Legacy: <code>http://...</code> (xend-http-server)</a>
|
||||
</h4>
|
||||
</h3>
|
||||
<p>
|
||||
If XenD is running and configured in <code>/etc/xen/xend-config.sxp</code>:
|
||||
|
||||
@ -276,17 +283,17 @@ Notes:
|
||||
libvirt, only the old-style sexpr interface known in the Xen
|
||||
documentation as "unix server" or "http server".</li>
|
||||
</ol>
|
||||
<h4>
|
||||
<h3>
|
||||
<a name="URI_legacy_xen">Legacy: <code>"xen"</code></a>
|
||||
</h4>
|
||||
</h3>
|
||||
<p>
|
||||
Another legacy URI is to specify name as the string
|
||||
<code>"xen"</code>. This will continue to refer to the Xen
|
||||
hypervisor. However you should prefer a full <a href="#URI_xen"><code>xen:///</code> URI</a> in all future code.
|
||||
</p>
|
||||
<h4>
|
||||
<h3>
|
||||
<a name="URI_legacy_proxy">Legacy: Xen proxy</a>
|
||||
</h4>
|
||||
</h3>
|
||||
<p>
|
||||
Libvirt continues to support connections to a separately running Xen
|
||||
proxy daemon. This provides a way to allow non-root users to make a
|
||||
|
@ -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;
|
||||
|
||||
|
||||
|
@ -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*
|
||||
|
@ -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
|
||||
|
@ -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 =
|
||||
|
158
src/libvirt.c
158
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");
|
||||
}
|
||||
|
12
src/libvirt.conf
Normal file
12
src/libvirt.conf
Normal file
@ -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",
|
||||
#]
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user