]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Allow for URI aliases when connecting to libvirt
authorDaniel P. Berrange <berrange@redhat.com>
Thu, 13 Oct 2011 10:49:45 +0000 (11:49 +0100)
committerDaniel P. Berrange <berrange@redhat.com>
Wed, 19 Oct 2011 08:14:34 +0000 (09:14 +0100)
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

docs/uri.html.in
include/libvirt/libvirt.h.in
libvirt.spec.in
mingw32-libvirt.spec.in
src/Makefile.am
src/libvirt.c
src/libvirt.conf [new file with mode: 0644]
src/remote/remote_driver.c
src/util/conf.c
src/xen/xen_driver.c

index e6326b23074f60af447fd366a78935a5f5a85029..79f878678c0274d7798a282ad94fe8064fd1e724 100644 (file)
@@ -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 &amp; 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 &gt;
 0.2.3.  For libvirt &#x2264; 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 &amp; 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
index 5f6a07a4dca704f54ef5011e92883cc1e1a14dd6..361881a018da9d18c1a2164917fadda7eb9a33a3 100644 (file)
@@ -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;
 
 
index 03bd7c72e875979e2ffd1e433fb6cff055e9f56d..262cfed0440af3bc4bd1a2567fe69c9c3df9dc53 100644 (file)
@@ -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*
index 521790ce9b4a9bb0deac6b61b4f9fcce81cd9b96..c2690f34dc3e8ab49ccfae317171d4473a7aac47 100644 (file)
@@ -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
index 87d91ede79cb8c407e8a2af9e592ad85d8ce1c73..07f27d2522911e8788cd3582f3214003b85fb82c 100644 (file)
@@ -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 =
index 69cffc5431382996cf40795a39c81981b15b24ea..0b975daecc86b157566d8ff97142703cc1b483f9 100644 (file)
@@ -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 (file)
index 0000000..c54903c
--- /dev/null
@@ -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",
+#]
index 4dc6974550cbbd5ed63a7c5d2aba5af4ada1c067..1dea327fb54be68928ba52b1f5a0305297aa030c 100644 (file)
@@ -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);
index 00045b54b4a1da3015593c905061e6b6d1e14aea..c8dcc7f9535a86629b0875f71848ba3d3f56bed3 100644 (file)
@@ -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) {
index 68abb1759aa22e4389e969dcd980bfd1e7798549..b3e7782890258a5536219e6f23f920d23dff30c7 100644 (file)
@@ -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;
         }
     }