Use systemd-tmpfiles to handle required directories at runtime when possible. (#21243)
* Use systemd-tmpfiles to handle required directories. This pushes handling of permissions and ownership of our required directories to systemd-tmpfiles when possible, which helps persistently ensure that they are correct, and allows us to make at least some Netdata service files both simpler and more reliable. * Address review comments. * Fix typos. * Update directory creation to be more robust. * Update tmpfiles config to more robustly ensure correct permissions. This adds new entries for the cloud.d and registry directories to be created, as well as adding entries to apply correct permissions and ownership for database files, claiming configuration, and a handful of other files.
Austin S. Hemmelgarn committed
Dec 3, 2025 at 11:29 UTC
0b04755a1039cb1d5651e19af35650feb71577a0
10 files changed
+103
-35
CMakeLists.txt
+11
@@ -3313,6 +3313,7 @@ set(libconfigdir_POST "${LIBCONFIG_DIR}")
3313
set(cachedir_POST "${CACHE_DIR}")
3314
set(varlibdir_POST "${VARLIB_DIR}")
3315
set(registrydir_POST "${VARLIB_DIR}/registry")
3316
+set(logdir_POST "${LOG_DIR}")
3317
set(netdata_user_POST "${NETDATA_USER}")
3318
set(netdata_group_POST "${NETDATA_USER}")
3319
@@ -3481,6 +3482,12 @@ install(FILES
3482
COMPONENT netdata
3483
DESTINATION usr/lib/netdata/system/systemd/sysusers)
3484
3485
+configure_file(system/systemd/tmpfiles.conf.in system/systemd/tmpfiles/netdata.conf @ONLY)
3486
+install(FILES
3487
+ ${CMAKE_BINARY_DIR}/system/systemd/tmpfiles/netdata.conf
3488
+ COMPONENT netdata
3489
+ DESTINATION usr/lib/netdata/system/systemd/tmpfiles)
3490
+
3491
if(BUILD_FOR_PACKAGING)
3492
install(FILES
3493
${CMAKE_BINARY_DIR}/system/systemd/netdata.service
@@ -3490,6 +3497,10 @@ if(BUILD_FOR_PACKAGING)
3497
${CMAKE_BINARY_DIR}/system/systemd/sysusers/netdata.conf
3498
COMPONENT user
3499
DESTINATION usr/lib/sysusers.d)
3500
+ install(FILES
3501
+ ${CMAKE_BINARY_DIR}/system/systemd/tmpfiles/netdata.conf
3502
+ COMPONENT netdata
3503
+ DESTINATION usr/lib/tmpfiles.d)
3504
install(DIRECTORY
3505
COMPONENT netdata
3506
DESTINATION usr/lib/systemd/journald@netdata.conf.d)
netdata-installer.sh
+3
-27
@@ -754,8 +754,8 @@ fi
754
[ -L "${NETDATA_USER_CONFIG_DIR}/orig" ] && run rm -f "${NETDATA_USER_CONFIG_DIR}/orig"
755
run ln -s "${NETDATA_STOCK_CONFIG_DIR}" "${NETDATA_USER_CONFIG_DIR}/orig"
756
757
-# --- web dir ----
757
758
+# --- web dir ---
759
if [ ! -d "${NETDATA_WEB_DIR}" ]; then
760
echo >&2 "Creating directory '${NETDATA_WEB_DIR}'"
761
run mkdir -p "${NETDATA_WEB_DIR}" || exit 1
@@ -763,33 +763,9 @@ fi
763
run find "${NETDATA_WEB_DIR}" -type f -exec chmod 0664 {} \;
764
run find "${NETDATA_WEB_DIR}" -type d -exec chmod 0775 {} \;
765
766
-# --- data dirs ----
766
+# --- other dirs ----
767
768
-for x in "${NETDATA_LIB_DIR}" "${NETDATA_CACHE_DIR}" "${NETDATA_LOG_DIR}"; do
769
- if [ ! -d "${x}" ]; then
770
- echo >&2 "Creating directory '${x}'"
771
- if ! run mkdir -p "${x}"; then
772
- warning "Failed to create ${x}, it must be created by hand or the Netdata Agent will not be able to be started."
773
- fi
774
- fi
775
-
776
- run chown -R "${NETDATA_USER}:${NETDATA_GROUP}" "${x}"
777
- #run find "${x}" -type f -exec chmod 0660 {} \;
778
- #run find "${x}" -type d -exec chmod 0770 {} \;
779
-done
780
-
781
-run chmod 755 "${NETDATA_LOG_DIR}"
782
-
783
-# --- claiming dir ----
784
-
785
-if [ ! -d "${NETDATA_CLAIMING_DIR}" ]; then
786
- echo >&2 "Creating directory '${NETDATA_CLAIMING_DIR}'"
787
- if ! run mkdir -p "${NETDATA_CLAIMING_DIR}"; then
788
- warning "failed to create ${NETDATA_CLAIMING_DIR}, it will need to be created manually."
789
- fi
790
-fi
791
-run chown -R "${NETDATA_USER}:${NETDATA_GROUP}" "${NETDATA_CLAIMING_DIR}"
792
-run chmod 770 "${NETDATA_CLAIMING_DIR}"
768
+install_netdata_dirs
769
770
# --- plugins ----
771
netdata.spec.in
+20
@@ -522,9 +522,28 @@ install -m 755 -d "${RPM_BUILD_ROOT}%{_presetdir}"
522
install -m 644 -p "system/systemd/50-%{name}.preset" "${RPM_BUILD_ROOT}%{_presetdir}/50-%{name}.preset"
523
install -m 755 -d "${RPM_BUILD_ROOT}%{_systemd_util_dir}/journald@%{name}.conf.d"
524
install -m 644 -p "system/systemd/journald@%{name}.conf" "${RPM_BUILD_ROOT}%{_systemd_util_dir}/journald@%{name}.conf.d/%{name}.conf"
525
+install -m 755 -d "${RPM_BUILD_ROOT}%{_tmpfilesdir}"
526
+install -m 644 -p "%{__cmake_builddir}/system/systemd/tmpfiles/%{name}.conf" "${RPM_BUILD_ROOT}%{_tmpfilesdir}/%{name}.conf"
527
install -m 755 -d "${RPM_BUILD_ROOT}%{_sysusersdir}"
528
install -m 644 -p "%{__cmake_builddir}/system/systemd/sysusers/%{name}.conf" "${RPM_BUILD_ROOT}%{_sysusersdir}/%{name}.conf"
529
530
+%pre
531
+
532
+if ! getent group %{name} > /dev/null; then
533
+ groupadd --system %{name}
534
+fi
535
+
536
+if ! getent passwd %{name} > /dev/null; then
537
+ useradd --system -g %{name} --home %{contentdir} --no-create-home -s /sbin/nologin -c "Netdata pseudo user" %{name}
538
+fi
539
+
540
+# I am not sure that the corresponding group names are exactly the same as in Debian, but we should start somewhere, shouldn't we?
541
+for item in docker nginx varnish haproxy adm nsd proxy squid ceph nobody I2C; do
542
+ if getent group $item > /dev/null 2>&1; then
543
+ usermod -a -G ${item} %{name}
544
+ fi
545
+done
546
+
547
%post
548
%if 0%{?suse_version}
549
%service_add_post %{name}.service
@@ -584,6 +603,7 @@ rm -rf "${RPM_BUILD_ROOT}"
603
%{_unitdir}/%{name}-updater.service
604
%{_presetdir}/50-%{name}.preset
605
%{_systemd_util_dir}/journald@%{name}.conf.d/%{name}.conf
606
+%{_tmpfilesdir}/%{name}.conf
607
608
%{_datarootdir}/%{name}/build-info-cmake-cache.gz
609
packaging/installer/functions.sh
+41
@@ -745,6 +745,47 @@ install_netdata_service() {
745
return 1
746
}
747
748
+install_netdata_tmpfiles() {
749
+ if [ "${UID}" -eq 0 ]; then
750
+ run mkdir -p /usr/lib/tmpfiles.d || return 1
751
+ run install -m 0644 -p "${NETDATA_PREFIX}/usr/lib/netdata/system/systemd/tmpfiles/netdata.conf" /usr/lib/tmpfiles.d/netdata.conf || return 1
752
+ return 0
753
+ else
754
+ return 1
755
+ fi
756
+}
757
+
758
+install_netdata_dirs() {
759
+ _DIRS_INSTALLED=0
760
+ if install_netdata_tmpfiles && command -v systemd-tmpfiles >/dev/null 2>&1 ; then
761
+ systemd-tmpfiles --create /usr/lib/tmpfiles.d/netdata.conf && _DIRS_INSTALLED=1
762
+ fi
763
+
764
+ if [ "${_DIRS_INSTALLED}" -eq 0 ]; then
765
+ for x in "${NETDATA_LIB_DIR}" "${NETDATA_CACHE_DIR}" "${NETDATA_LOG_DIR}"; do
766
+ if [ ! -d "${x}" ]; then
767
+ echo >&2 "Creating directory '${x}'"
768
+ if ! run mkdir -p "${x}"; then
769
+ warning "Failed to create ${x}, it must be created by hand or the Netdata Agent will not be able to be started."
770
+ fi
771
+ fi
772
+
773
+ run chown -R "${NETDATA_USER}:${NETDATA_GROUP}" "${x}"
774
+ done
775
+
776
+ run chmod 755 "${NETDATA_LOG_DIR}"
777
+
778
+ if [ ! -d "${NETDATA_CLAIMING_DIR}" ]; then
779
+ echo >&2 "Creating directory '${NETDATA_CLAIMING_DIR}'"
780
+ if ! run mkdir -p "${NETDATA_CLAIMING_DIR}"; then
781
+ warning "failed to create ${NETDATA_CLAIMING_DIR}, it will need to be created manually."
782
+ fi
783
+ fi
784
+ run chown -R "${NETDATA_USER}:${NETDATA_GROUP}" "${NETDATA_CLAIMING_DIR}"
785
+ run chmod 770 "${NETDATA_CLAIMING_DIR}"
786
+ fi
787
+}
788
+
789
# -----------------------------------------------------------------------------
790
# stop netdata
791
packaging/installer/netdata-uninstaller.sh
+1
@@ -811,6 +811,7 @@ fi
811
812
rm_file /etc/logrotate.d/netdata
813
rm_file /etc/init.d/netdata
814
+rm_file /usr/lib/tmpfiles.d/netdata.conf
815
rm_file /Library/LaunchDaemons/com.github.netdata.plist
816
817
if [ -n "${NETDATA_PREFIX}" ] && [ -d "${NETDATA_PREFIX}" ] && [ "netdata" = "$(basename "$NETDATA_PREFIX")" ] ; then
packaging/makeself/install-or-update.sh
+2
-1
@@ -169,7 +169,8 @@ progress "fix permissions"
169
170
run chmod g+rx,o+rx /opt
171
run find /opt/netdata -type d -exec chmod go+rx '{}' \+
172
-run chown -R ${NETDATA_USER}:${NETDATA_GROUP} /opt/netdata/var
172
+
173
+install_netdata_dirs
174
175
if [ -d /opt/netdata/usr/libexec/netdata/plugins.d/ebpf.d ]; then
176
run chown -R root:${NETDATA_GROUP} /opt/netdata/usr/libexec/netdata/plugins.d/ebpf.d
system/openrc/init.d/netdata.in
+6
-1
@@ -16,8 +16,13 @@ command_args="-P ${NETDATA_PIDFILE} ${NETDATA_EXTRA_ARGS}"
16
command_args_foreground="-D"
17
18
depend() {
19
+ # Gentoo and its derivatives still use systemd-tmpfiles even with OpenRC, Alpine does not.
20
+ if rc-service --exists systemd-tmpfiles-setup; then
21
+ need net systemd-tmpfiles-setup
22
+ else
23
+ need net
24
+ fi
25
use logger
20
- need net
26
after apache2 squid nginx mysql named opensips upsd hostapd postfix lm_sensors
27
}
28
system/systemd/netdata.service.in
+2
-4
@@ -3,8 +3,8 @@
3
Description=Netdata, X-Ray Vision for your infrastructure!
4
5
# append here other services you want netdata to wait for them to start
6
-After=network.target network-online.target nss-lookup.target
7
-Wants=network-online.target nss-lookup.target
6
+After=systemd-tmpfiles-setup.service network.target network-online.target nss-lookup.target
7
+Wants=systemd-tmpfiles-setup.service network-online.target nss-lookup.target
8
9
[Service]
10
LogNamespace=netdata
@@ -15,8 +15,6 @@ RuntimeDirectory=netdata
15
RuntimeDirectoryMode=0775
16
PIDFile=/run/netdata/netdata.pid
17
ExecStart=@sbindir_POST@/netdata -P /run/netdata/netdata.pid -D
18
-ExecStartPre=/bin/mkdir -p @localstatedir_POST@/cache/netdata
19
-ExecStartPre=/bin/chown -R @netdata_user_POST@ @localstatedir_POST@/cache/netdata
18
PermissionsStartOnly=true
19
20
# saving a big db on slow disks may need some time
system/systemd/netdata.service.v235.in
+2
-2
@@ -3,8 +3,8 @@
3
Description=Netdata, X-Ray Vision for your infrastructure!
4
5
# append here other services you want netdata to wait for them to start
6
-After=network.target network-online.target nss-lookup.target
7
-Wants=network-online.target nss-lookup.target
6
+After=systemd-tmpfiles-setup.service network.target network-online.target nss-lookup.target
7
+Wants=systemd-tmpfiles-setup.service network-online.target nss-lookup.target
8
9
[Service]
10
LogNamespace=netdata
system/systemd/tmpfiles.conf.in
new
+15
@@ -0,0 +1,15 @@
1
+d /run/netdata 0755 @netdata_user_POST@ @netdata_group_POST@ -
2
+
3
+d @cachedir_POST@ 0755 @netdata_user_POST@ @netdata_group_POST@ -
4
+z @cachedir_POST@/dbengine* 0750 @netdata_user_POST@ @netdata_group_POST@ -
5
+z @cachedir_POST@/dbengine*/* 0600 @netdata_user_POST@ @netdata_group_POST@ -
6
+z @cachedir_POST@/*-meta.db* 0660 @netdata_user_POST@ @netdata_group_POST@ -
7
+
8
+d @varlibdir_POST@ 0770 @netdata_user_POST@ @netdata_group_POST@ -
9
+d @varlibdir_POST@/cloud.d 0770 @netdata_user_POST@ @netdata_group_POST@ -
10
+z @varlibdir_POST@/cloud.d/* 0660 @netdata_user_POST@ @netdata_group_POST@ -
11
+d @varlibdir_POST@/registry 0770 @netdata_user_POST@ @netdata_group_POST@ -
12
+z @varlibdir_POST@/registry/netdata.public.unique.id 0660 @netdata_user_POST@ @netdata_group_POST@ -
13
+z @varlibdir_POST@/netdata.api.key 0660 @netdata_user_POST@ @netdata_group_POST@ -
14
+
15
+d @logdir_POST@ 0755 @netdata_user_POST@ @netdata_group_POST@ -