[libvirt] [PATCH 12/15] Add support for admin API in libvirt daemon

Martin Kletzander mkletzan at redhat.com
Thu Apr 16 14:46:47 UTC 2015


For this to pe properly separated from other protocols used by the
server, there is second subserver added which allows access to the whole
virNetServer to its clients.

Signed-off-by: Martin Kletzander <mkletzan at redhat.com>
---
 cfg.mk                |  3 ++
 daemon/Makefile.am    | 33 +++++++++++++++++-
 daemon/admin_server.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++
 daemon/admin_server.h | 36 +++++++++++++++++++
 daemon/libvirtd.c     | 91 ++++++++++++++++++++++++++++++++++++++++++-----
 daemon/libvirtd.h     | 14 +++++++-
 po/POTFILES.in        |  1 +
 7 files changed, 264 insertions(+), 11 deletions(-)
 create mode 100644 daemon/admin_server.c
 create mode 100644 daemon/admin_server.h

diff --git a/cfg.mk b/cfg.mk
index b948b7a..7c1c597 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -1072,6 +1072,7 @@ sc_po_check: \
 		$(srcdir)/daemon/remote_dispatch.h \
 		$(srcdir)/daemon/qemu_dispatch.h \
 		$(srcdir)/src/remote/remote_client_bodies.h \
+		$(srcdir)/daemon/admin_dispatch.h \
 		$(srcdir)/src/admin/admin_client.h
 $(srcdir)/daemon/remote_dispatch.h: $(srcdir)/src/remote/remote_protocol.x
 	$(MAKE) -C daemon remote_dispatch.h
@@ -1079,6 +1080,8 @@ $(srcdir)/daemon/qemu_dispatch.h: $(srcdir)/src/remote/qemu_protocol.x
 	$(MAKE) -C daemon qemu_dispatch.h
 $(srcdir)/src/remote/remote_client_bodies.h: $(srcdir)/src/remote/remote_protocol.x
 	$(MAKE) -C src remote/remote_client_bodies.h
+$(srcdir)/daemon/admin_server.h: $(srcdir)/src/admin/admin_protocol.x
+	$(MAKE) -C daemon admin_dispatch.h
 $(srcdir)/src/admin/admin_client.h: $(srcdir)/src/admin/admin_protocol.x
 	$(MAKE) -C src admin/admin_client.h

diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index bceaeb2..b309ce9 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -1,6 +1,6 @@
 ## Process this file with automake to produce Makefile.in

-## Copyright (C) 2005-2014 Red Hat, Inc.
+## Copyright (C) 2005-2015 Red Hat, Inc.
 ##
 ## This library is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU Lesser General Public
@@ -25,6 +25,7 @@ INCLUDES = \
 	-I$(top_srcdir)/src/conf \
 	-I$(top_srcdir)/src/rpc \
 	-I$(top_srcdir)/src/remote \
+	-I$(top_srcdir)/src/admin \
 	-I$(top_srcdir)/src/access \
 	$(GETTEXT_CPPFLAGS)

@@ -49,6 +50,7 @@ EXTRA_DIST =						\
 	remote_dispatch.h				\
 	lxc_dispatch.h					\
 	qemu_dispatch.h					\
+	admin_dispatch.h				\
 	libvirtd.conf					\
 	libvirtd.init.in				\
 	libvirtd.upstart				\
@@ -76,6 +78,9 @@ BUILT_SOURCES =
 REMOTE_PROTOCOL = $(top_srcdir)/src/remote/remote_protocol.x
 LXC_PROTOCOL = $(top_srcdir)/src/remote/lxc_protocol.x
 QEMU_PROTOCOL = $(top_srcdir)/src/remote/qemu_protocol.x
+ADMIN_PROTOCOL = $(top_srcdir)/src/admin/admin_protocol.x
+
+BUILT_SOURCES += admin_dispatch.h

 remote_dispatch.h: $(srcdir)/../src/rpc/gendispatch.pl \
 		$(REMOTE_PROTOCOL)
@@ -95,6 +100,12 @@ qemu_dispatch.h: $(srcdir)/../src/rpc/gendispatch.pl \
 	  --mode=server qemu QEMU $(QEMU_PROTOCOL) \
 	  > $(srcdir)/qemu_dispatch.h

+admin_dispatch.h: $(srcdir)/../src/rpc/gendispatch.pl \
+		$(ADMIN_PROTOCOL)
+	$(AM_V_GEN)$(PERL) -w $(srcdir)/../src/rpc/gendispatch.pl \
+	  --mode=server admin ADMIN $(ADMIN_PROTOCOL) \
+	  > $(srcdir)/admin_dispatch.h
+
 if WITH_LIBVIRTD

 # Build a convenience library, for reuse in tests/libvirtdconftest
@@ -114,6 +125,25 @@ libvirtd_conf_la_LDFLAGS =				\
 	$(NULL)
 libvirtd_conf_la_LIBADD = $(LIBXML_LIBS)

+noinst_LTLIBRARIES += libvirtd_admin.la
+libvirtd_admin_la_SOURCES = \
+		admin_server.c \
+		../src/admin/admin_protocol.c
+
+libvirtd_admin_la_CFLAGS = \
+		$(AM_CFLAGS)		\
+		$(XDR_CFLAGS)		\
+		$(PIE_CFLAGS)		\
+		$(WARN_CFLAGS)		\
+		$(LIBXML_CFLAGS)	\
+		$(COVERAGE_CFLAGS)
+
+libvirtd_admin_la_LDFLAGS = \
+		$(PIE_LDFLAGS)		\
+		$(RELRO_LDFLAGS)	\
+		$(COVERAGE_LDFLAGS)	\
+		$(NO_INDIRECT_LDFLAGS)
+
 man8_MANS = libvirtd.8

 sbin_PROGRAMS = libvirtd
@@ -166,6 +196,7 @@ endif WITH_DTRACE_PROBES

 libvirtd_LDADD += \
 	libvirtd_conf.la \
+	libvirtd_admin.la \
 	../src/libvirt-lxc.la \
 	../src/libvirt-qemu.la \
 	../src/libvirt_driver_remote.la \
diff --git a/daemon/admin_server.c b/daemon/admin_server.c
new file mode 100644
index 0000000..3f0939a
--- /dev/null
+++ b/daemon/admin_server.c
@@ -0,0 +1,97 @@
+/*
+ * admin_server.c:
+ *
+ * Copyright (C) 2014-2015 Red Hat, Inc.
+ *
+ * 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, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Martin Kletzander <mkletzan at redhat.com>
+ */
+
+#include <config.h>
+
+#include "internal.h"
+#include "libvirtd.h"
+#include "libvirt_internal.h"
+
+#include "admin_protocol.h"
+#include "admin_server.h"
+#include "datatypes.h"
+#include "viralloc.h"
+#include "virerror.h"
+#include "virlog.h"
+#include "virnetserver.h"
+#include "virstring.h"
+#include "virthreadjob.h"
+
+#define VIR_FROM_THIS VIR_FROM_ADMIN
+
+VIR_LOG_INIT("daemon.admin");
+
+
+void
+remoteAdmClientFreeFunc(void *data)
+{
+    VIR_FREE(data);
+}
+
+void *
+remoteAdmClientInitHook(virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                        void *opaque)
+{
+    struct daemonAdmClientPrivate *priv;
+
+    if (VIR_ALLOC(priv) < 0)
+        return NULL;
+
+    if (virMutexInit(&priv->lock) < 0) {
+        VIR_FREE(priv);
+        virReportSystemError(errno, "%s", _("unable to init mutex"));
+        return NULL;
+    }
+
+    priv->srv = opaque;
+
+    return priv;
+}
+
+/* Functions */
+static int
+adminDispatchConnectOpen(virNetSubServerPtr subserver ATTRIBUTE_UNUSED,
+                         virNetServerClientPtr client,
+                         virNetMessagePtr msg ATTRIBUTE_UNUSED,
+                         virNetMessageErrorPtr rerr,
+                         struct admin_connect_open_args *args)
+{
+    unsigned int flags;
+    struct daemonAdmClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
+    int ret = -1;
+
+    VIR_DEBUG("priv=%p srv=%p", priv, priv->srv);
+    virMutexLock(&priv->lock);
+
+    flags = args->flags;
+    virCheckFlagsGoto(0, cleanup);
+
+    ret = 0;
+ cleanup:
+    if (ret < 0)
+        virNetMessageSaveError(rerr);
+    virMutexUnlock(&priv->lock);
+    return ret;
+}
+
+#include "admin_dispatch.h"
diff --git a/daemon/admin_server.h b/daemon/admin_server.h
new file mode 100644
index 0000000..26721a6
--- /dev/null
+++ b/daemon/admin_server.h
@@ -0,0 +1,36 @@
+/*
+ * admin_server.h
+ *
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Martin Kletzander <mkletzan at redhat.com>
+ */
+
+#ifndef __LIBVIRTD_ADMIN_H__
+# define __LIBVIRTD_ADMIN_H__
+
+# include "rpc/virnetserverprogram.h"
+# include "rpc/virnetserverclient.h"
+
+
+extern virNetServerProgramProc adminProcs[];
+extern size_t adminNProcs;
+
+void remoteAdmClientFreeFunc(void *data);
+void *remoteAdmClientInitHook(virNetServerClientPtr client, void *opaque);
+
+#endif /* __ADMIN_REMOTE_H__ */
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index e209e93..e041771 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -44,6 +44,7 @@
 #include "libvirtd.h"
 #include "libvirtd-config.h"

+#include "admin_server.h"
 #include "viruuid.h"
 #include "remote_driver.h"
 #include "viralloc.h"
@@ -112,6 +113,7 @@ VIR_LOG_INIT("daemon.libvirtd");
 virNetSASLContextPtr saslCtxt = NULL;
 #endif
 virNetServerProgramPtr remoteProgram = NULL;
+virNetServerProgramPtr adminProgram = NULL;
 virNetServerProgramPtr qemuProgram = NULL;
 virNetServerProgramPtr lxcProgram = NULL;

@@ -253,18 +255,24 @@ static int
 daemonUnixSocketPaths(struct daemonConfig *config,
                       bool privileged,
                       char **sockfile,
-                      char **rosockfile)
+                      char **rosockfile,
+                      char **admsockfile)
 {
     if (config->unix_sock_dir) {
         if (virAsprintf(sockfile, "%s/libvirt-sock", config->unix_sock_dir) < 0)
             goto error;
-        if (privileged &&
-            virAsprintf(rosockfile, "%s/libvirt-sock-ro", config->unix_sock_dir) < 0)
-            goto error;
+
+        if (privileged) {
+            if (virAsprintf(rosockfile, "%s/libvirt-sock-ro", config->unix_sock_dir) < 0)
+                goto error;
+            if (virAsprintf(admsockfile, "%s/libvirt-admin-sock", config->unix_sock_dir) < 0)
+                goto error;
+        }
     } else {
         if (privileged) {
             if (VIR_STRDUP(*sockfile, LOCALSTATEDIR "/run/libvirt/libvirt-sock") < 0 ||
-                VIR_STRDUP(*rosockfile, LOCALSTATEDIR "/run/libvirt/libvirt-sock-ro") < 0)
+                VIR_STRDUP(*rosockfile, LOCALSTATEDIR "/run/libvirt/libvirt-sock-ro") < 0 ||
+                VIR_STRDUP(*admsockfile, LOCALSTATEDIR "/run/libvirt/libvirt-admin-sock") < 0)
                 goto error;
         } else {
             char *rundir = NULL;
@@ -429,10 +437,12 @@ daemonSetupNetworking(virNetServerPtr srv,
                       struct daemonConfig *config,
                       const char *sock_path,
                       const char *sock_path_ro,
+                      const char *sock_path_adm,
                       bool ipsock,
                       bool privileged)
 {
     virNetServerServicePtr svc = NULL;
+    virNetServerServicePtr svcAdm = NULL;
     virNetServerServicePtr svcRO = NULL;
     virNetServerServicePtr svcTCP = NULL;
 #if WITH_GNUTLS
@@ -441,6 +451,7 @@ daemonSetupNetworking(virNetServerPtr srv,
     gid_t unix_sock_gid = 0;
     int unix_sock_ro_mask = 0;
     int unix_sock_rw_mask = 0;
+    int unix_sock_adm_mask = 0;

     unsigned int cur_fd = STDERR_FILENO + 1;
     unsigned int nfds = virGetListenFDs();
@@ -460,6 +471,11 @@ daemonSetupNetworking(virNetServerPtr srv,
         goto error;
     }

+    if (virStrToLong_i(config->unix_sock_admin_perms, NULL, 8, &unix_sock_adm_mask) != 0) {
+        VIR_ERROR(_("Failed to parse mode '%s'"), config->unix_sock_admin_perms);
+        goto error;
+    }
+
     if (virStrToLong_i(config->unix_sock_rw_perms, NULL, 8, &unix_sock_rw_mask) != 0) {
         VIR_ERROR(_("Failed to parse mode '%s'"), config->unix_sock_rw_perms);
         goto error;
@@ -502,6 +518,25 @@ daemonSetupNetworking(virNetServerPtr srv,
         virNetServerAddService(srv, 0, svcRO, NULL) < 0)
         goto error;

+    if (sock_path_adm) {
+        VIR_DEBUG("Registering unix socket %s", sock_path_adm);
+        if (!(svcAdm = virNetServerServiceNewUNIX(sock_path_adm,
+                                                  unix_sock_adm_mask,
+                                                  unix_sock_gid,
+                                                  REMOTE_AUTH_NONE,
+#if WITH_GNUTLS
+                                                  NULL,
+#endif
+                                                  true,
+                                                  config->max_queued_clients,
+                                                  config->max_client_requests)))
+            goto error;
+    }
+
+    if (svcAdm &&
+        virNetServerAddService(srv, 1, svcAdm, NULL) < 0)
+        goto error;
+
     if (ipsock) {
         if (config->listen_tcp) {
             VIR_DEBUG("Registering TCP socket %s:%s",
@@ -599,6 +634,7 @@ daemonSetupNetworking(virNetServerPtr srv,
     virObjectUnref(svcTCP);
     virObjectUnref(svc);
     virObjectUnref(svcRO);
+    virObjectUnref(svcAdm);
     return -1;
 }

@@ -1105,6 +1141,7 @@ int main(int argc, char **argv) {
     char *pid_file = NULL;
     char *sock_file = NULL;
     char *sock_file_ro = NULL;
+    char *sock_file_adm = NULL;
     int timeout = -1;        /* -t: Shutdown timeout */
     int verbose = 0;
     int godaemon = 0;
@@ -1272,12 +1309,15 @@ int main(int argc, char **argv) {
     if (daemonUnixSocketPaths(config,
                               privileged,
                               &sock_file,
-                              &sock_file_ro) < 0) {
+                              &sock_file_ro,
+                              &sock_file_adm) < 0) {
         VIR_ERROR(_("Can't determine socket paths"));
         exit(EXIT_FAILURE);
     }
-    VIR_DEBUG("Decided on socket paths '%s' and '%s'",
-              sock_file, NULLSTR(sock_file_ro));
+    VIR_DEBUG("Decided on socket paths '%s', '%s' and '%s'",
+              sock_file,
+              NULLSTR(sock_file_ro),
+              NULLSTR(sock_file_adm));

     if (godaemon) {
         char ebuf[1024];
@@ -1408,6 +1448,35 @@ int main(int argc, char **argv) {
         goto cleanup;
     }

+    if (virNetServerAddSubServer(srv,
+                                 config->min_workers,
+                                 config->max_workers,
+                                 config->prio_workers,
+                                 config->max_clients,
+                                 config->max_anonymous_clients,
+                                 config->keepalive_interval,
+                                 config->keepalive_count,
+                                 !!config->keepalive_required,
+                                 remoteAdmClientInitHook,
+                                 NULL,
+                                 remoteAdmClientFreeFunc,
+                                 srv) < 0) {
+        ret = VIR_DAEMON_ERR_INIT;
+        goto cleanup;
+    }
+
+    if (!(adminProgram = virNetServerProgramNew(ADMIN_PROGRAM,
+                                                ADMIN_PROTOCOL_VERSION,
+                                                adminProcs,
+                                                adminNProcs))) {
+        ret = VIR_DAEMON_ERR_INIT;
+        goto cleanup;
+    }
+    if (virNetServerAddProgram(srv, 1, adminProgram) < 0) {
+        ret = VIR_DAEMON_ERR_INIT;
+        goto cleanup;
+    }
+
     if (timeout != -1) {
         VIR_DEBUG("Registering shutdown timeout %d", timeout);
         virNetServerAutoShutdown(srv,
@@ -1450,7 +1519,9 @@ int main(int argc, char **argv) {
                 0, "start", NULL, NULL);

     if (daemonSetupNetworking(srv, config,
-                              sock_file, sock_file_ro,
+                              sock_file,
+                              sock_file_ro,
+                              sock_file_adm,
                               ipsock, privileged) < 0) {
         ret = VIR_DAEMON_ERR_NETWORK;
         goto cleanup;
@@ -1503,6 +1574,7 @@ int main(int argc, char **argv) {
     virObjectUnref(remoteProgram);
     virObjectUnref(lxcProgram);
     virObjectUnref(qemuProgram);
+    virObjectUnref(adminProgram);
     virNetServerClose(srv);
     virObjectUnref(srv);
     virNetlinkShutdown();
@@ -1521,6 +1593,7 @@ int main(int argc, char **argv) {

     VIR_FREE(sock_file);
     VIR_FREE(sock_file_ro);
+    VIR_FREE(sock_file_adm);
     VIR_FREE(pid_file);
     VIR_FREE(remote_config_file);
     VIR_FREE(run_dir);
diff --git a/daemon/libvirtd.h b/daemon/libvirtd.h
index 02d4101..81f68cc 100644
--- a/daemon/libvirtd.h
+++ b/daemon/libvirtd.h
@@ -1,7 +1,7 @@
 /*
  * libvirtd.h: daemon data structure definitions
  *
- * Copyright (C) 2006-2014 Red Hat, Inc.
+ * Copyright (C) 2006-2015 Red Hat, Inc.
  * Copyright (C) 2006 Daniel P. Berrange
  *
  * This library is free software; you can redistribute it and/or
@@ -30,9 +30,11 @@
 # include <rpc/types.h>
 # include <rpc/xdr.h>
 # include "remote_protocol.h"
+# include "admin_protocol.h"
 # include "lxc_protocol.h"
 # include "qemu_protocol.h"
 # include "virthread.h"
+
 # if WITH_SASL
 #  include "virnetsaslcontext.h"
 # endif
@@ -42,6 +44,8 @@ typedef struct daemonClientStream daemonClientStream;
 typedef daemonClientStream *daemonClientStreamPtr;
 typedef struct daemonClientPrivate daemonClientPrivate;
 typedef daemonClientPrivate *daemonClientPrivatePtr;
+typedef struct daemonAdmClientPrivate daemonAdmClientPrivate;
+typedef daemonAdmClientPrivate *daemonAdmClientPrivatePtr;
 typedef struct daemonClientEventCallback daemonClientEventCallback;
 typedef daemonClientEventCallback *daemonClientEventCallbackPtr;

@@ -71,6 +75,14 @@ struct daemonClientPrivate {
     bool keepalive_supported;
 };

+/* Separate private data for admin connection */
+struct daemonAdmClientPrivate {
+    /* Just a placeholder, not that there is anything to be locked */
+    virMutex lock;
+
+    virNetServerPtr srv;
+};
+
 # if WITH_SASL
 extern virNetSASLContextPtr saslCtxt;
 # endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index af07e09..0378166 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,3 +1,4 @@
+daemon/admin_server.c
 daemon/libvirtd-config.c
 daemon/libvirtd.c
 daemon/qemu_dispatch.h
-- 
2.3.5




More information about the libvir-list mailing list