daemon: basic systemd integration
Notify systemd when NFD is ready/reloading/terminating
Change-Id: I833b48fbcaf6ecc2c4bb8a1da67d4eb9a050c116
Refs: #2815
diff --git a/.jenkins.d/00-deps.sh b/.jenkins.d/00-deps.sh
index 6bf3ddd..a9b3a34 100755
--- a/.jenkins.d/00-deps.sh
+++ b/.jenkins.d/00-deps.sh
@@ -25,7 +25,7 @@
if has Ubuntu $NODE_LABELS; then
sudo apt-get -qq update
sudo apt-get -qy install build-essential pkg-config libboost-all-dev \
- libsqlite3-dev libssl-dev libpcap-dev
+ libsqlite3-dev libssl-dev libpcap-dev libsystemd-dev
if [[ $JOB_NAME == *"code-coverage" ]]; then
sudo apt-get -qy install lcov libgd-perl python-setuptools
@@ -34,9 +34,10 @@
fi
if has CentOS $NODE_LABELS; then
- sudo yum -y install yum-utils pkgconfig libpcap-devel \
+ sudo yum -y install yum-utils pkgconfig \
openssl-devel libtranslit-icu \
python-devel sqlite-devel \
+ libpcap-devel systemd-devel \
devtoolset-7-libasan-devel \
devtoolset-7-liblsan-devel
sudo yum -y groupinstall 'Development Tools'
diff --git a/contrib/systemd/README.md b/contrib/systemd/README.md
index 7c722ab..d129b5e 100644
--- a/contrib/systemd/README.md
+++ b/contrib/systemd/README.md
@@ -1,8 +1,8 @@
Starting NFD on Linux with systemd
==================================
-Newer versions of Ubuntu (starting with 15.04) and some other Linux distributions, including Debian
-use systemd to start system daemons, monitor their health, and restart them when they die.
+Modern versions of Ubuntu (starting with 15.04) and some other Linux distributions, including Debian
+and Fedora, use systemd to start system daemons, monitor their health, and restart them when they die.
Initial setup
-------------
@@ -127,4 +127,4 @@
To permanently stop the `nfd` daemon and disable it from being automatically started on reboot,
disable the service:
- sudo systemctl disable nfd
\ No newline at end of file
+ sudo systemctl disable nfd
diff --git a/contrib/systemd/nfd.service b/contrib/systemd/nfd.service
index 063e4a7..57661fd 100644
--- a/contrib/systemd/nfd.service
+++ b/contrib/systemd/nfd.service
@@ -30,9 +30,10 @@
After=network-online.target
[Service]
+Type=notify
Environment=HOME=/usr/local/var/lib/ndn/nfd
ExecStart=/usr/local/bin/nfd --config /usr/local/etc/ndn/nfd.conf
-ExecStartPost=/bin/sh -ec 'sleep 2; if [ -f /usr/local/etc/ndn/nfd-init.sh ]; then . /usr/local/etc/ndn/nfd-init.sh; fi'
+ExecStartPost=/bin/sh -ec 'if [ -f /usr/local/etc/ndn/nfd-init.sh ]; then . /usr/local/etc/ndn/nfd-init.sh; fi'
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartPreventExitStatus=2 4
diff --git a/daemon/main.cpp b/daemon/main.cpp
index f6d482d..5999ea1 100644
--- a/daemon/main.cpp
+++ b/daemon/main.cpp
@@ -54,6 +54,9 @@
#ifdef HAVE_LIBPCAP
#include <pcap/pcap.h>
#endif
+#ifdef HAVE_SYSTEMD
+#include <systemd/sd-daemon.h>
+#endif
#ifdef HAVE_WEBSOCKET
#include <websocketpp/version.hpp>
#endif
@@ -151,6 +154,7 @@
}
try {
+ systemdNotify("READY=1");
mainIo->run();
}
catch (const std::exception& e) {
@@ -175,6 +179,15 @@
return retval;
}
+ static void
+ systemdNotify(const char* state)
+ {
+#ifdef HAVE_SYSTEMD
+ sd_notify(0, state);
+#endif
+ }
+
+private:
void
terminate(const boost::system::error_code& error, int signalNo)
{
@@ -182,6 +195,8 @@
return;
NFD_LOG_INFO("Caught signal '" << ::strsignal(signalNo) << "', exiting...");
+
+ systemdNotify("STOPPING=1");
getGlobalIoService().stop();
}
@@ -192,7 +207,10 @@
return;
NFD_LOG_INFO("Caught signal '" << ::strsignal(signalNo) << "', reloading...");
+
+ systemdNotify("RELOADING=1");
m_nfd.reloadConfigFile();
+ systemdNotify("READY=1");
m_reloadSignalSet.async_wait(bind(&NfdRunner::reload, this, _1, _2));
}
diff --git a/wscript b/wscript
index c5f8b33..6773293 100644
--- a/wscript
+++ b/wscript
@@ -41,15 +41,16 @@
tooldir=['.waf-tools'])
nfdopt = opt.add_option_group('NFD Options')
- opt.addUnixOptions(nfdopt)
- opt.addWebsocketOptions(nfdopt)
+ opt.addUnixOptions(nfdopt)
+ opt.addDependencyOptions(nfdopt, 'libresolv')
+ opt.addDependencyOptions(nfdopt, 'librt')
opt.addDependencyOptions(nfdopt, 'libpcap')
nfdopt.add_option('--without-libpcap', action='store_true', default=False,
help='Disable libpcap (Ethernet face support will be disabled)')
-
- opt.addDependencyOptions(nfdopt, 'librt')
- opt.addDependencyOptions(nfdopt, 'libresolv')
+ nfdopt.add_option('--without-systemd', action='store_true', default=False,
+ help='Disable systemd integration')
+ opt.addWebsocketOptions(nfdopt)
nfdopt.add_option('--with-tests', action='store_true', default=False,
help='Build unit tests')
@@ -87,6 +88,13 @@
'pch', 'boost', 'dependency-checker', 'websocket',
'doxygen', 'sphinx_build'])
+ if conf.options.with_tests:
+ conf.env.WITH_TESTS = True
+ conf.define('WITH_TESTS', 1)
+ if conf.options.with_other_tests:
+ conf.env.WITH_OTHER_TESTS = True
+ conf.define('WITH_OTHER_TESTS', 1)
+
conf.find_program('bash', var='BASH')
if 'PKG_CONFIG_PATH' not in os.environ:
@@ -94,6 +102,9 @@
conf.check_cfg(package='libndn-cxx', args=['--cflags', '--libs'],
uselib_store='NDN_CXX', mandatory=True)
+ conf.check_cfg(package='libsystemd', args=['--cflags', '--libs'],
+ uselib_store='SYSTEMD', mandatory=False)
+
conf.checkDependency(name='librt', lib='rt', mandatory=False)
conf.checkDependency(name='libresolv', lib='resolv', mandatory=False)
@@ -103,14 +114,6 @@
conf.check_cxx(header_name='valgrind/valgrind.h', define_name='HAVE_VALGRIND', mandatory=False)
- if conf.options.with_tests:
- conf.env.WITH_TESTS = True
- conf.define('WITH_TESTS', 1)
-
- if conf.options.with_other_tests:
- conf.env.WITH_OTHER_TESTS = True
- conf.define('WITH_OTHER_TESTS', 1)
-
boost_libs = 'system chrono program_options thread log log_setup'
if conf.options.with_tests or conf.options.with_other_tests:
boost_libs += ' unit_test_framework'
@@ -122,13 +125,14 @@
' (https://redmine.named-data.net/projects/nfd/wiki/Boost_FAQ)')
conf.load('unix-socket')
- conf.checkWebsocket(mandatory=True)
if not conf.options.without_libpcap:
conf.checkDependency(name='libpcap', lib='pcap', mandatory=True,
errmsg='not found, but required for Ethernet face support. '
'Specify --without-libpcap to disable Ethernet face support.')
+ conf.checkWebsocket(mandatory=True)
+
conf.check_compiler_flags()
# Loading "late" to prevent tests from being compiled with profiling flags
@@ -201,7 +205,7 @@
bld.program(name='nfd',
target='bin/nfd',
source='daemon/main.cpp',
- use='daemon-objects rib-objects')
+ use='daemon-objects rib-objects SYSTEMD')
bld.recurse('tools')
bld.recurse('tests')