From: "Daniel P. Berrange" <berrange@xxxxxxxxxx> 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list