Use paths specified from environment variables for /etc configuration files
Some configuration files that need updates are directly under in /etc. To update them atomically, we need write access to /etc. For Ubuntu Core this is an issue as /etc is not writable. Only a selection of subdirectories can be writable. The general solution is symlinks or bind mounts to writable places. But for atomic writes in /etc, that does not work. So Ubuntu has had a patch for that that did not age well. Instead we would like to introduce some environment variables for alternate paths. * SYSTEMD_ETC_HOSTNAME: /etc/hostname * SYSTEMD_ETC_MACHINE_INFO: /etc/machine-info * SYSTEMD_ETC_LOCALTIME: /etc/localtime * SYSTEMD_ETC_LOCALE_CONF: /etc/locale.conf * SYSTEMD_ETC_VCONSOLE_CONF: /etc/vconsole.conf * SYSTEMD_ETC_ADJTIME: /etc/adjtime While it is for now expected that there is a symlink from the standard, we still try to read them from that alternate path. This is important for `/etc/localtime`, which is a symlink, so we cannot have an indirect symlink or bind mount for it. Since machine-id is typically written only once and not updated. This commit does not cover it. An initrd can properly create it and bind mount it.
This commit is contained in:
committed by
Lennart Poettering
parent
fa34fda2eb
commit
0dc39dffbd
@@ -33,6 +33,34 @@ timedatectl set-time "$future_time"
|
||||
|
||||
while test ! -f /tmp/clock-changed ; do sleep .5 ; done
|
||||
|
||||
mkdir -p /etc/alternate-path
|
||||
rm -f /etc/alternate-path/localtime
|
||||
|
||||
cat <<EOF >/run/systemd/system.conf
|
||||
[Manager]
|
||||
ManagerEnvironment=SYSTEMD_ETC_LOCALTIME=/etc/alternate-path/localtime
|
||||
EOF
|
||||
mkdir -p /run/systemd/system/systemd-timedated.service.d
|
||||
cat >/run/systemd/system/systemd-timedated.service.d/override.conf <<EOF
|
||||
[Service]
|
||||
Environment=SYSTEMD_ETC_LOCALTIME=/run/alternate-path/mylocaltime
|
||||
Environment=SYSTEMD_ETC_ADJTIME=/run/alternate-path/myadjtime
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
|
||||
systemd-run --on-timezone-change touch /tmp/timezone-changed-alternate-path-1
|
||||
timedatectl set-timezone Europe/Berlin
|
||||
|
||||
while test ! -f /tmp/timezone-changed-alternate-path-1 ; do sleep .5 ; done
|
||||
|
||||
systemd-run --on-timezone-change touch /tmp/timezone-changed-alternate-path-2
|
||||
timedatectl set-timezone Europe/Kyiv
|
||||
|
||||
while test ! -f /tmp/timezone-changed-alternate-path-2 ; do sleep .5 ; done
|
||||
|
||||
rm /run/systemd/system.conf /run/systemd/system/systemd-timedated.service.d/override.conf
|
||||
systemctl daemon-reload
|
||||
|
||||
systemd-analyze log-level info
|
||||
|
||||
touch /testok
|
||||
|
||||
@@ -403,6 +403,50 @@ EOF
|
||||
rm -f /run/systemd/network/ntp99.*
|
||||
}
|
||||
|
||||
teardown_timedated_alternate_paths() {
|
||||
set +eu
|
||||
|
||||
rm -rf /run/systemd/system/systemd-timedated.service.d
|
||||
systemctl daemon-reload
|
||||
systemctl restart systemd-timedated
|
||||
}
|
||||
|
||||
testcase_timedated_alternate_paths() {
|
||||
trap teardown_timedated_alternate_paths RETURN
|
||||
|
||||
mkdir -p /run/alternate-path
|
||||
mkdir -p /run/systemd/system/systemd-timedated.service.d
|
||||
cat >/run/systemd/system/systemd-timedated.service.d/override.conf <<EOF
|
||||
[Service]
|
||||
Environment=SYSTEMD_ETC_LOCALTIME=/run/alternate-path/mylocaltime
|
||||
Environment=SYSTEMD_ETC_ADJTIME=/run/alternate-path/myadjtime
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
systemctl restart systemd-timedated
|
||||
|
||||
assert_in "Local time:" "$(timedatectl --no-pager)"
|
||||
|
||||
assert_eq "$(timedatectl --no-pager set-timezone Europe/Kyiv 2>&1)" ""
|
||||
assert_eq "$(readlink /run/alternate-path/mylocaltime | sed 's#^.*zoneinfo/##')" "Europe/Kyiv"
|
||||
assert_in "Time zone: Europe/Kyiv \(EES*T, \+0[0-9]00\)" "$(timedatectl)"
|
||||
|
||||
# Restart to force using get_timezine
|
||||
systemctl restart systemd-timedated
|
||||
assert_in "Time zone: Europe/Kyiv \(EES*T, \+0[0-9]00\)" "$(timedatectl)"
|
||||
|
||||
assert_in "RTC in local TZ: no" "$(timedatectl --no-pager)"
|
||||
assert_rc 0 timedatectl set-local-rtc 1
|
||||
assert_in "RTC in local TZ: yes" "$(timedatectl --no-pager)"
|
||||
assert_eq "$(cat /run/alternate-path/myadjtime)" "0.0 0 0
|
||||
0
|
||||
LOCAL"
|
||||
assert_rc 0 timedatectl set-local-rtc 0
|
||||
if [[ -e /run/alternate-path/myadjtime ]]; then
|
||||
echo "/run/alternate-path/myadjtime still exists" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
run_testcases
|
||||
|
||||
touch /testok
|
||||
|
||||
@@ -278,6 +278,45 @@ test_wildcard() {
|
||||
hostnamectl set-hostname "$SAVED"
|
||||
}
|
||||
|
||||
teardown_hostnamed_alternate_paths() {
|
||||
set +eu
|
||||
|
||||
rm -rf /run/systemd/system/systemd-hostnamed.service.d
|
||||
systemctl daemon-reload
|
||||
systemctl restart systemd-hostnamed
|
||||
if [[ -f /etc/hostname ]]; then
|
||||
orig=$(cat /etc/hostname)
|
||||
if [[ -n "${orig}" ]]; then
|
||||
hostnamectl hostname "${orig}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
testcase_hostnamed_alternate_paths() {
|
||||
trap teardown_hostnamed_alternate_paths RETURN
|
||||
|
||||
mkdir -p /run/alternate-path
|
||||
|
||||
mkdir -p /run/systemd/system/systemd-hostnamed.service.d
|
||||
cat >/run/systemd/system/systemd-hostnamed.service.d/override.conf <<EOF
|
||||
[Service]
|
||||
Environment=SYSTEMD_ETC_HOSTNAME=/run/alternate-path/myhostname
|
||||
Environment=SYSTEMD_ETC_MACHINE_INFO=/run/alternate-path/mymachine-info
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
systemctl restart systemd-hostnamed
|
||||
|
||||
assert_rc 0 hostnamectl set-hostname heisenberg
|
||||
assert_rc 0 hostnamectl chassis watch
|
||||
|
||||
output=$(hostnamectl)
|
||||
assert_in "Static hostname: heisenberg" "$output"
|
||||
assert_in "Chassis: watch" "$output"
|
||||
assert_in "heisenberg" "$(cat /run/alternate-path/myhostname)"
|
||||
assert_in "CHASSIS=watch" "$(cat /run/alternate-path/mymachine-info)"
|
||||
}
|
||||
|
||||
|
||||
run_testcases
|
||||
|
||||
touch /testok
|
||||
|
||||
@@ -651,6 +651,53 @@ testcase_locale_gen_leading_space() {
|
||||
localectl set-locale en_US.UTF-8
|
||||
}
|
||||
|
||||
teardown_localed_alternate_paths() {
|
||||
set +eu
|
||||
|
||||
rm -rf /run/systemd/system/systemd-localed.service.d
|
||||
systemctl daemon-reload
|
||||
systemctl restart systemd-localed
|
||||
}
|
||||
|
||||
testcase_localed_alternate_paths() {
|
||||
trap teardown_localed_alternate_paths RETURN
|
||||
|
||||
mkdir -p /run/alternate-path
|
||||
|
||||
mkdir -p /run/systemd/system/systemd-localed.service.d
|
||||
cat >/run/systemd/system/systemd-localed.service.d/override.conf <<EOF
|
||||
[Service]
|
||||
Environment=SYSTEMD_ETC_LOCALE_CONF=/run/alternate-path/mylocale.conf
|
||||
Environment=SYSTEMD_ETC_VCONSOLE_CONF=/run/alternate-path/myvconsole.conf
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
systemctl restart systemd-localed
|
||||
|
||||
if localectl list-locales | grep "^de_DE.UTF-8$"; then
|
||||
assert_rc 0 localectl set-locale "LANG=de_DE.UTF-8" "LC_CTYPE=C"
|
||||
else
|
||||
skip_locale=1
|
||||
fi
|
||||
|
||||
if localectl list-keymaps | grep -F "^no$"; then
|
||||
assert_rc 0 localectl set-keymap "no"
|
||||
else
|
||||
skip_keymap=1
|
||||
fi
|
||||
|
||||
output=$(localectl)
|
||||
|
||||
if [[ -z "${skip_locale-}" ]]; then
|
||||
assert_in "System Locale: LANG=de_DE.UTF-8" "$output"
|
||||
assert_in "LANG=de_DE.UTF-8" "$(cat /run/alternate-path/mylocale.conf)"
|
||||
fi
|
||||
|
||||
if [[ -z "${skip_keymap-}" ]]; then
|
||||
assert_in "VC Keymap: no" "$output"
|
||||
assert_in "KEYMAP=no" "$(cat /run/alternate-path/myvconsole.conf)"
|
||||
fi
|
||||
}
|
||||
|
||||
# Make sure the content of kbd-model-map is the one that the tests expect
|
||||
# regardless of the version installed on the distro where the testsuite is
|
||||
# running on.
|
||||
|
||||
@@ -18,6 +18,10 @@ at_exit() {
|
||||
rm -fr "$ROOT"
|
||||
fi
|
||||
|
||||
if [[ -d /etc/otherpath ]]; then
|
||||
rm -rf /etc/otherpath
|
||||
fi
|
||||
|
||||
restore_locale
|
||||
}
|
||||
|
||||
@@ -282,3 +286,36 @@ rm -fv "$ROOT/etc/passwd" "$ROOT/etc/shadow"
|
||||
(! systemd-firstboot --root="$ROOT" --root-shell=/bin/nonexistentshell)
|
||||
(! systemd-firstboot --root="$ROOT" --machine-id=invalidmachineid)
|
||||
(! systemd-firstboot --root="$ROOT" --timezone=Foo/Bar)
|
||||
|
||||
mkdir -p "${ROOT}/etc/otherpath"
|
||||
mkdir -p /etc/otherpath
|
||||
echo "KEYMAP=us" >/etc/otherpath/vconsole.conf
|
||||
echo "LANG=en_US.UTF-8" >/etc/otherpath/locale.conf
|
||||
ln -s "../$(readlink /etc/localtime)" /etc/otherpath/localtime
|
||||
|
||||
SYSTEMD_ETC_LOCALE_CONF=/etc/otherpath/locale.conf \
|
||||
SYSTEMD_ETC_VCONSOLE_CONF=/etc/otherpath/vconsole.conf \
|
||||
SYSTEMD_ETC_LOCALTIME=/etc/otherpath/localtime \
|
||||
SYSTEMD_ETC_HOSTNAME=/etc/otherpath/hostname \
|
||||
systemd-firstboot --root="$ROOT" --copy-locale --copy-keymap --copy-timezone --hostname="weirdpaths"
|
||||
|
||||
diff "${ROOT}/etc/otherpath/locale.conf" "/etc/otherpath/locale.conf"
|
||||
diff "${ROOT}/etc/otherpath/vconsole.conf" "/etc/otherpath/vconsole.conf"
|
||||
grep -q "weirdpaths" "${ROOT}/etc/otherpath/hostname"
|
||||
|
||||
[[ "$(readlink /etc/otherpath/localtime)" = "$(readlink "${ROOT}/etc/otherpath/localtime")" ]]
|
||||
|
||||
SYSTEMD_ETC_LOCALE_CONF=/etc/otherpath/locale.conf \
|
||||
SYSTEMD_ETC_VCONSOLE_CONF=/etc/otherpath/vconsole.conf \
|
||||
SYSTEMD_ETC_LOCALTIME=/etc/otherpath/localtime \
|
||||
SYSTEMD_ETC_HOSTNAME=/etc/otherpath/hostname \
|
||||
systemd-firstboot --root="$ROOT" --force \
|
||||
--hostname="weirdpaths2" \
|
||||
--locale=no_NO.UTF-8 \
|
||||
--keymap=no \
|
||||
--timezone=Europe/Oslo
|
||||
|
||||
grep -q "LANG=no_NO.UTF-8" "${ROOT}/etc/otherpath/locale.conf"
|
||||
grep -q "KEYMAP=no" "${ROOT}/etc/otherpath/vconsole.conf"
|
||||
grep -q "weirdpaths2" "${ROOT}/etc/otherpath/hostname"
|
||||
[[ "$(readlink "${ROOT}/etc/otherpath/localtime")" = "../../usr/share/zoneinfo/Europe/Oslo" ]]
|
||||
|
||||
Reference in New Issue
Block a user