[PATCH 10/13] Add support for admin API in libvirt daemon

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

Signed-off-by: Martin Kletzander <mkletzan@xxxxxxxxxx>
---
 cfg.mk                |   3 ++
 daemon/Makefile.am    |  32 +++++++++++++-
 daemon/admin_server.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++
 daemon/admin_server.h |  36 ++++++++++++++++
 daemon/libvirtd.c     | 104 +++++++++++++++++++++++++++++++++++++++-----
 daemon/libvirtd.h     |  14 +++++-
 po/POTFILES.in        |   1 +
 7 files changed, 294 insertions(+), 13 deletions(-)
 create mode 100644 daemon/admin_server.c
 create mode 100644 daemon/admin_server.h

diff --git a/cfg.mk b/cfg.mk
index f1b50242c6df..0d1a03ce807b 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_dispatch.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 42dec5d79c65..3d45f2a804d5 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)

@@ -34,6 +35,7 @@ DAEMON_GENERATED =			\
 		remote_dispatch.h	\
 		lxc_dispatch.h		\
 		qemu_dispatch.h		\
+		admin_dispatch.h	\
 		$(NULL)

 DAEMON_SOURCES =					\
@@ -49,6 +51,7 @@ EXTRA_DIST =						\
 	remote_dispatch.h				\
 	lxc_dispatch.h					\
 	qemu_dispatch.h					\
+	admin_dispatch.h				\
 	libvirtd.conf					\
 	libvirtd.init.in				\
 	libvirtd.upstart				\
@@ -78,6 +81,7 @@ 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

 remote_dispatch.h: $(top_srcdir)/src/rpc/gendispatch.pl \
 		$(REMOTE_PROTOCOL)
@@ -97,6 +101,12 @@ qemu_dispatch.h: $(top_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
@@ -116,6 +126,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
@@ -168,6 +197,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 000000000000..712a44beca10
--- /dev/null
+++ b/daemon/admin_server.c
@@ -0,0 +1,117 @@
+/*
+ * 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@xxxxxxxxxx>
+ */
+
+#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 "virnetdaemon.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)
+{
+    struct daemonAdmClientPrivate *priv = data;
+
+    virMutexDestroy(&priv->lock);
+    virObjectUnref(priv->dmn);
+    VIR_FREE(priv);
+}
+
+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;
+    }
+
+    /*
+     * We don't necessarily need to ref this object right now as there
+     * must be one ref being held throughout the life of the daemon,
+     * but let's just be safe for future.
+     */
+    priv->dmn = virObjectRef(opaque);
+
+    return priv;
+}
+
+/* Functions */
+static int
+adminDispatchConnectOpen(virNetServerPtr server 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 dmn=%p", priv, priv->dmn);
+    virMutexLock(&priv->lock);
+
+    flags = args->flags;
+    virCheckFlagsGoto(0, cleanup);
+
+    ret = 0;
+ cleanup:
+    if (ret < 0)
+        virNetMessageSaveError(rerr);
+    virMutexUnlock(&priv->lock);
+    return ret;
+}
+
+static int
+adminDispatchConnectClose(virNetServerPtr server ATTRIBUTE_UNUSED,
+                          virNetServerClientPtr client,
+                          virNetMessagePtr msg ATTRIBUTE_UNUSED,
+                          virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED)
+{
+    virNetServerClientDelayedClose(client);
+    return 0;
+}
+
+#include "admin_dispatch.h"
diff --git a/daemon/admin_server.h b/daemon/admin_server.h
new file mode 100644
index 000000000000..26721a6d582b
--- /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@xxxxxxxxxx>
+ */
+
+#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 94103e2d0d8c..368e10ca3549 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;
@@ -280,7 +288,8 @@ daemonUnixSocketPaths(struct daemonConfig *config,
             }
             umask(old_umask);

-            if (virAsprintf(sockfile, "%s/libvirt-sock", rundir) < 0) {
+            if (virAsprintf(sockfile, "%s/libvirt-sock", rundir) < 0 ||
+                virAsprintf(admsockfile, "%s/libvirt-admin-sock", rundir) < 0) {
                 VIR_FREE(rundir);
                 goto error;
             }
@@ -427,13 +436,16 @@ static void daemonInitialize(void)

 static int ATTRIBUTE_NONNULL(3)
 daemonSetupNetworking(virNetServerPtr srv,
+                      virNetServerPtr srvAdm,
                       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
@@ -442,6 +454,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();
@@ -461,6 +474,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;
@@ -503,6 +521,24 @@ daemonSetupNetworking(virNetServerPtr srv,
         virNetServerAddService(srv, 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->admin_max_queued_clients,
+                                                  config->admin_max_client_requests)))
+            goto error;
+    }
+
+    if (virNetServerAddService(srvAdm, svcAdm, NULL) < 0)
+        goto error;
+
     if (ipsock) {
         if (config->listen_tcp) {
             VIR_DEBUG("Registering TCP socket %s:%s",
@@ -602,6 +638,7 @@ daemonSetupNetworking(virNetServerPtr srv,
     virObjectUnref(svcTCP);
     virObjectUnref(svc);
     virObjectUnref(svcRO);
+    virObjectUnref(svcAdm);
     return -1;
 }

@@ -1102,6 +1139,7 @@ daemonUsage(const char *argv0, bool privileged)
 int main(int argc, char **argv) {
     virNetDaemonPtr dmn = NULL;
     virNetServerPtr srv = NULL;
+    virNetServerPtr srvAdm = NULL;
     char *remote_config_file = NULL;
     int statuswrite = -1;
     int ret = 1;
@@ -1109,6 +1147,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;
@@ -1276,12 +1315,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];
@@ -1413,6 +1455,40 @@ int main(int argc, char **argv) {
         goto cleanup;
     }

+    if (!(srvAdm = virNetServerNew(config->admin_min_workers,
+                                   config->admin_max_workers,
+                                   0,
+                                   config->admin_max_clients,
+                                   0,
+                                   config->admin_keepalive_interval,
+                                   config->admin_keepalive_count,
+                                   !!config->admin_keepalive_required,
+                                   NULL,
+                                   remoteAdmClientInitHook,
+                                   NULL,
+                                   remoteAdmClientFreeFunc,
+                                   dmn))) {
+        ret = VIR_DAEMON_ERR_INIT;
+        goto cleanup;
+    }
+
+    if (virNetDaemonAddServer(dmn, srvAdm) < 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(srvAdm, adminProgram) < 0) {
+        ret = VIR_DAEMON_ERR_INIT;
+        goto cleanup;
+    }
+
     if (timeout != -1) {
         VIR_DEBUG("Registering shutdown timeout %d", timeout);
         virNetDaemonAutoShutdown(dmn, timeout);
@@ -1453,8 +1529,11 @@ int main(int argc, char **argv) {
     virHookCall(VIR_HOOK_DRIVER_DAEMON, "-", VIR_HOOK_DAEMON_OP_START,
                 0, "start", NULL, NULL);

-    if (daemonSetupNetworking(srv, config,
-                              sock_file, sock_file_ro,
+    if (daemonSetupNetworking(srv, srvAdm,
+                              config,
+                              sock_file,
+                              sock_file_ro,
+                              sock_file_adm,
                               ipsock, privileged) < 0) {
         ret = VIR_DAEMON_ERR_NETWORK;
         goto cleanup;
@@ -1507,9 +1586,11 @@ int main(int argc, char **argv) {
     virObjectUnref(remoteProgram);
     virObjectUnref(lxcProgram);
     virObjectUnref(qemuProgram);
+    virObjectUnref(adminProgram);
     virNetDaemonClose(dmn);
     virObjectUnref(dmn);
     virObjectUnref(srv);
+    virObjectUnref(srvAdm);
     virNetlinkShutdown();
     if (statuswrite != -1) {
         if (ret != 0) {
@@ -1526,6 +1607,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 02d4101742d8..8c1a904893ab 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;
+
+    virNetDaemonPtr dmn;
+};
+
 # if WITH_SASL
 extern virNetSASLContextPtr saslCtxt;
 # endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 4afa2f920824..189e2cc2f4d9 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.4.3

--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list



[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]