[libvirt] [PATCH 14/14] Enable systemd socket activation with virtlockd

Daniel P. Berrange berrange at redhat.com
Thu Jul 7 14:17:32 UTC 2011


From: "Daniel P. Berrange" <berrange at redhat.com>

This enhancement virtlockd so that it can receive a pre-opened
UNIX domain socket from systemd at launch time, and adds the
systemd service/socket unit files

* daemon/libvirtd.service.in: Require virtlockd to be running
* libvirt.spec.in: Add virtlockd systemd files
* src/Makefile.am: Install systemd files
* src/locking/lock_daemon.c: Support socket activation
* src/locking/virtlockd.service.in, src/locking/virtlockd.socket.in:
  systemd unit files
* src/rpc/virnetserverservice.c, src/rpc/virnetserverservice.h:
  Add virNetServerServiceNewFD() method
* src/rpc/virnetsocket.c, src/rpc/virnetsocket.h: Add virNetSocketNewListenFD
  method
---
 daemon/libvirtd.service.in       |    2 +
 libvirt.spec.in                  |    6 +++
 src/.gitignore                   |    2 +
 src/Makefile.am                  |   51 +++++++++++++++++++++++++-
 src/locking/lock_daemon.c        |   73 ++++++++++++++++++++++++++++++++++++-
 src/locking/virtlockd.service.in |   16 ++++++++
 src/locking/virtlockd.socket.in  |    5 +++
 src/rpc/virnetserverservice.c    |   48 +++++++++++++++++++++++++
 src/rpc/virnetserverservice.h    |    5 +++
 src/rpc/virnetsocket.c           |   20 ++++++++++
 src/rpc/virnetsocket.h           |    3 ++
 11 files changed, 227 insertions(+), 4 deletions(-)
 create mode 100644 src/locking/virtlockd.service.in
 create mode 100644 src/locking/virtlockd.socket.in

diff --git a/daemon/libvirtd.service.in b/daemon/libvirtd.service.in
index 9661428..1cc0ae8 100644
--- a/daemon/libvirtd.service.in
+++ b/daemon/libvirtd.service.in
@@ -9,7 +9,9 @@ After=syslog.target
 After=udev.target
 After=avahi.target
 After=dbus.target
+After=virtlockd.service
 Before=libvirt-guests.service
+Requires=virtlockd.service
 
 [Service]
 EnvironmentFile=-/etc/sysconfig/libvirtd
diff --git a/libvirt.spec.in b/libvirt.spec.in
index 7f6fd13..ccc3db3 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -892,6 +892,7 @@ done
 %if %{with_systemd}
 if [ $1 -eq 1 ] ; then
     # Initial installation
+    /bin/systemctl enable virtlockd.service >/dev/null 2>&1 || :
     /bin/systemctl enable libvirtd.service >/dev/null 2>&1 || :
     /bin/systemctl enable cgconfig.service >/dev/null 2>&1 || :
 fi
@@ -914,8 +915,10 @@ fi
 %if %{with_systemd}
 if [ $1 -eq 0 ] ; then
     # Package removal, not upgrade
+    /bin/systemctl --no-reload disable virtlockd.service > /dev/null 2>&1 || :
     /bin/systemctl --no-reload disable libvirtd.service > /dev/null 2>&1 || :
     /bin/systemctl stop libvirtd.service > /dev/null 2>&1 || :
+    /bin/systemctl stop virtlockd.service > /dev/null 2>&1 || :
 fi
 %else
 if [ $1 = 0 ]; then
@@ -931,6 +934,7 @@ fi
 /bin/systemctl daemon-reload >/dev/null 2>&1 || :
 if [ $1 -ge 1 ] ; then
     # Package upgrade, not uninstall
+    /bin/systemctl try-restart virtlockd.service >/dev/null 2>&1 || :
     /bin/systemctl try-restart libvirtd.service >/dev/null 2>&1 || :
 fi
 %endif
@@ -1010,6 +1014,8 @@ fi
 %{_sysconfdir}/rc.d/init.d/virtlockd
 %if %{with_systemd}
 %{_unitdir}/libvirtd.service
+%{_unitdir}/virtlockd.service
+%{_unitdir}/virtlockd.socket
 %endif
 %doc daemon/libvirtd.upstart
 %config(noreplace) %{_sysconfdir}/sysconfig/libvirtd
diff --git a/src/.gitignore b/src/.gitignore
index c499b47..58729ca 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -17,6 +17,8 @@ libvirt_qemu.def
 remote_protocol-structs-t
 virt-aa-helper
 virtlockd
+virtlockd.service
+virtlockd.init
 virtlockd.socket
 locking/lock_daemon_dispatch_stubs.h
 locking/qemu-sanlock.conf
diff --git a/src/Makefile.am b/src/Makefile.am
index 9a9deab..b14381b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1283,6 +1283,53 @@ virtlockd.init: locking/virtlockd.init.in $(top_builddir)/config.status
 
 
 
+EXTRA_DIST += locking/virtlockd.service.in locking/virtlockd.socket.in
+
+if WITH_LIBVIRTD
+if LIBVIRT_INIT_SCRIPT_SYSTEMD
+
+SYSTEMD_UNIT_DIR = /lib/systemd/system
+
+BUILT_SOURCES += virtlockd.service virtlockd.socket
+
+install-systemd: virtlockd.init install-sysconfig
+	mkdir -p $(DESTDIR)$(SYSTEMD_UNIT_DIR)
+	$(INSTALL_SCRIPT) virtlockd.service \
+	  $(DESTDIR)$(SYSTEMD_UNIT_DIR)/
+	$(INSTALL_SCRIPT) virtlockd.socket \
+	  $(DESTDIR)$(SYSTEMD_UNIT_DIR)/
+
+uninstall-systemd: uninstall-sysconfig
+	rm -f $(DESTDIR)$(SYSTEMD_UNIT_DIR)/virtlockd.service
+	rm -f $(DESTDIR)$(SYSTEMD_UNIT_DIR)/virtlockd.socket
+else
+install-systemd:
+uninstall-systemd:
+endif
+else
+install-systemd:
+uninstall-systemd:
+endif
+
+virtlockd.service: locking/virtlockd.service.in $(top_builddir)/config.status
+	$(AM_V_GEN)sed					\
+	    -e s!\@localstatedir\@!@localstatedir@!g	\
+	    -e s!\@sbindir\@!@sbindir@!g		\
+	    -e s!\@sysconfdir\@!@sysconfdir@!g		\
+	    < $< > $@-t &&				\
+	    chmod a+x $@-t &&				\
+	    mv $@-t $@
+
+virtlockd.socket: locking/virtlockd.socket.in $(top_builddir)/config.status
+	$(AM_V_GEN)sed					\
+	    -e s!\@localstatedir\@!@localstatedir@!g	\
+	    -e s!\@sbindir\@!@sbindir@!g		\
+	    -e s!\@sysconfdir\@!@sysconfdir@!g		\
+	    < $< > $@-t &&				\
+	    chmod a+x $@-t &&				\
+	    mv $@-t $@
+
+
 if HAVE_SANLOCK
 lockdriver_LTLIBRARIES += sanlock.la
 sanlock_la_SOURCES = $(LOCK_DRIVER_SANLOCK_SOURCES)
@@ -1466,7 +1513,7 @@ endif
 endif
 EXTRA_DIST += $(SECURITY_DRIVER_APPARMOR_HELPER_SOURCES)
 
-install-data-local: install-init
+install-data-local: install-init install-systemd
 if WITH_LIBVIRTD
 	$(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/lockd"
 	$(MKDIR_P) "$(DESTDIR)$(localstatedir)/run/libvirt/lockd"
@@ -1512,7 +1559,7 @@ if WITH_NETWORK
 	    $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart/default.xml
 endif
 
-uninstall-local:: uninstall-init
+uninstall-local:: uninstall-init uninstall-systemd
 if WITH_LIBVIRTD
 	rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/lockd" ||:
 	rmdir "$(DESTDIR)$(localstatedir)/run/libvirt/lockd" ||:
diff --git a/src/locking/lock_daemon.c b/src/locking/lock_daemon.c
index 1c20715..797cbe8 100644
--- a/src/locking/lock_daemon.c
+++ b/src/locking/lock_daemon.c
@@ -418,8 +418,69 @@ virLockDaemonSetupSignals(virNetServerPtr srv)
     return 0;
 }
 
+
+static int
+virLockDaemonSetupNetworkingSystemD(virNetServerPtr srv)
+{
+    virNetServerServicePtr svc;
+    const char *pidstr;
+    const char *fdstr;
+    unsigned long long pid;
+    unsigned int nfds;
+
+    if (!(pidstr = getenv("LISTEN_PID"))) {
+        VIR_DEBUG("No LISTEN_FDS from systemd");
+        return 0;
+    }
+
+    if (virStrToLong_ull(pidstr, NULL, 10, &pid) < 0) {
+        VIR_DEBUG("Malformed LISTEN_PID from systemd %s", pidstr);
+        return 0;
+    }
+
+    if ((pid_t)pid != getpid()) {
+        VIR_DEBUG("LISTEN_PID %s is not for us %llu",
+                  pidstr, (unsigned long long)getpid());
+        return 0;
+    }
+
+    if (!(fdstr = getenv("LISTEN_FDS"))) {
+        VIR_DEBUG("No LISTEN_FDS from systemd");
+        return 0;
+    }
+
+    if (virStrToLong_ui(fdstr, NULL, 10, &nfds) < 0) {
+        VIR_DEBUG("Malformed LISTEN_FDS from systemd %s", fdstr);
+        return 0;
+    }
+
+    if (nfds > 1) {
+        VIR_DEBUG("Too many (%d) file descriptors from systemd",
+                  nfds);
+        nfds = 1;
+    }
+
+    unsetenv("LISTEN_PID");
+    unsetenv("LISTEN_FDS");
+
+    if (nfds == 0)
+        return 0;
+
+    /* Systemd passes FDs, starting immediately after stderr,
+     * so the first FD we'll get is '3'. */
+    if (!(svc = virNetServerServiceNewFD(3, 0, false, 1, NULL)))
+        return -1;
+
+    if (virNetServerAddService(srv, svc, NULL) < 0) {
+        virNetServerServiceFree(svc);
+        return -1;
+    }
+    return 1;
+}
+
+
 static int
-virLockDaemonSetupNetworking(virNetServerPtr srv, const char *sock_path)
+virLockDaemonSetupNetworkingNative(virNetServerPtr srv, const char *sock_path)
 {
     virNetServerServicePtr svc;
 
@@ -563,6 +624,7 @@ int main(int argc, char **argv) {
     char *pid_file = NULL;
     int pid_file_fd = -1;
     char *sock_file = NULL;
+    int rv;
 
     struct option opts[] = {
         { "verbose", no_argument, &verbose, 1},
@@ -724,7 +786,14 @@ int main(int argc, char **argv) {
     }
 
 
-    if (virLockDaemonSetupNetworking(srv, sock_file) < 0) {
+    if ((rv = virLockDaemonSetupNetworkingSystemD(srv)) < 0) {
+        ret = VIR_LOCK_DAEMON_ERR_NETWORK;
+        goto cleanup;
+    }
+
+    /* Only do this, if systemd did not pass a FD */
+    if (rv == 0 &&
+        virLockDaemonSetupNetworkingNative(srv, sock_file) < 0) {
         ret = VIR_LOCK_DAEMON_ERR_NETWORK;
         goto cleanup;
     }
diff --git a/src/locking/virtlockd.service.in b/src/locking/virtlockd.service.in
new file mode 100644
index 0000000..5a74545
--- /dev/null
+++ b/src/locking/virtlockd.service.in
@@ -0,0 +1,16 @@
+[Unit]
+Description=Virtual machine lock manager
+Requires=virtlockd.socket
+After=syslog.target
+
+[Service]
+EnvironmentFile=-/etc/sysconfig/virtlockd
+ExecStart=@sbindir@/virtlockd
+ExecReload=/bin/kill -HUP $MAINPID
+# Loosing the locks is a really bad thing that will
+# cause the machine to be fenced (rebooted), so make
+# sure we discourage OOM killer
+OOMScoreAdjust=-900
+
+[Install]
+WantedBy=multi-user.target
diff --git a/src/locking/virtlockd.socket.in b/src/locking/virtlockd.socket.in
new file mode 100644
index 0000000..5d57aed
--- /dev/null
+++ b/src/locking/virtlockd.socket.in
@@ -0,0 +1,5 @@
+[Unit]
+Description=Virtual machine lock manager socket
+
+[Socket]
+ListenStream=/var/run/libvirt/lockd/lockd.sock
diff --git a/src/rpc/virnetserverservice.c b/src/rpc/virnetserverservice.c
index 8c250e2..560f996 100644
--- a/src/rpc/virnetserverservice.c
+++ b/src/rpc/virnetserverservice.c
@@ -197,6 +197,54 @@ error:
     return NULL;
 }
 
+virNetServerServicePtr virNetServerServiceNewFD(int fd,
+                                                int auth,
+                                                bool readonly,
+                                                size_t nrequests_client_max,
+                                                virNetTLSContextPtr tls)
+{
+    virNetServerServicePtr svc;
+    int i;
+
+    if (VIR_ALLOC(svc) < 0)
+        goto no_memory;
+
+    svc->refs = 1;
+    svc->auth = auth;
+    svc->readonly = readonly;
+    svc->nrequests_client_max = nrequests_client_max;
+    svc->tls = tls;
+    if (tls)
+        virNetTLSContextRef(tls);
+
+    svc->nsocks = 1;
+    if (VIR_ALLOC_N(svc->socks, svc->nsocks) < 0)
+        goto no_memory;
+
+    if (virNetSocketNewListenFD(fd,
+                                &svc->socks[0]) < 0)
+        goto error;
+
+    for (i = 0 ; i < svc->nsocks ; i++) {
+        /* IO callback is initially disabled, until we're ready
+         * to deal with incoming clients */
+        if (virNetSocketAddIOCallback(svc->socks[i],
+                                      0,
+                                      virNetServerServiceAccept,
+                                      svc) < 0)
+            goto error;
+    }
+
+
+    return svc;
+
+no_memory:
+    virReportOOMError();
+error:
+    virNetServerServiceFree(svc);
+    return NULL;
+}
+
 
 int virNetServerServiceGetPort(virNetServerServicePtr svc)
 {
diff --git a/src/rpc/virnetserverservice.h b/src/rpc/virnetserverservice.h
index 9357598..fa5d71c 100644
--- a/src/rpc/virnetserverservice.h
+++ b/src/rpc/virnetserverservice.h
@@ -49,6 +49,11 @@ virNetServerServicePtr virNetServerServiceNewUNIX(const char *path,
                                                   bool readonly,
                                                   size_t nrequests_client_max,
                                                   virNetTLSContextPtr tls);
+virNetServerServicePtr virNetServerServiceNewFD(int fd,
+                                                int auth,
+                                                bool readonly,
+                                                size_t nrequests_client_max,
+                                                virNetTLSContextPtr tls);
 
 int virNetServerServiceGetPort(virNetServerServicePtr svc);
 
diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c
index aff68bc..b5d66f5 100644
--- a/src/rpc/virnetsocket.c
+++ b/src/rpc/virnetsocket.c
@@ -348,6 +348,26 @@ int virNetSocketNewListenUNIX(const char *path ATTRIBUTE_UNUSED,
 }
 #endif
 
+int virNetSocketNewListenFD(int fd,
+                            virNetSocketPtr *retsock)
+{
+    virSocketAddr addr;
+    *retsock = NULL;
+
+    memset(&addr, 0, sizeof(addr));
+
+    addr.len = sizeof(addr.data);
+    if (getsockname(fd, &addr.data.sa, &addr.len) < 0) {
+        virReportSystemError(errno, "%s", _("Unable to get local socket name"));
+        return -1;
+    }
+
+    if (!(*retsock = virNetSocketNew(&addr, NULL, false, fd, -1, 0)))
+        return -1;
+
+    return 0;
+}
+
 
 int virNetSocketNewConnectTCP(const char *nodename,
                               const char *service,
diff --git a/src/rpc/virnetsocket.h b/src/rpc/virnetsocket.h
index 8053213..f0e6a37 100644
--- a/src/rpc/virnetsocket.h
+++ b/src/rpc/virnetsocket.h
@@ -50,6 +50,9 @@ int virNetSocketNewListenUNIX(const char *path,
                               gid_t grp,
                               virNetSocketPtr *addr);
 
+int virNetSocketNewListenFD(int fd,
+                            virNetSocketPtr *addr);
+
 int virNetSocketNewConnectTCP(const char *nodename,
                               const char *service,
                               virNetSocketPtr *addr);
-- 
1.7.6




More information about the libvir-list mailing list