Merge pull request #25004 from keszybz/transient-drop-ins
Allow drop-ins for transient units
This commit is contained in:
@@ -957,7 +957,7 @@ static int transient_unit_from_message(
|
||||
|
||||
if (!unit_is_pristine(u))
|
||||
return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS,
|
||||
"Unit %s already exists.", name);
|
||||
"Unit %s was already loaded or has a fragment file.", name);
|
||||
|
||||
/* OK, the unit failed to load and is unreferenced, now let's
|
||||
* fill in the transient data instead */
|
||||
|
||||
+13
-11
@@ -4844,18 +4844,20 @@ int unit_fail_if_noncanonical(Unit *u, const char* where) {
|
||||
bool unit_is_pristine(Unit *u) {
|
||||
assert(u);
|
||||
|
||||
/* Check if the unit already exists or is already around,
|
||||
* in a number of different ways. Note that to cater for unit
|
||||
* types such as slice, we are generally fine with units that
|
||||
* are marked UNIT_LOADED even though nothing was actually
|
||||
* loaded, as those unit types don't require a file on disk. */
|
||||
/* Check if the unit already exists or is already around, in a number of different ways. Note that to
|
||||
* cater for unit types such as slice, we are generally fine with units that are marked UNIT_LOADED
|
||||
* even though nothing was actually loaded, as those unit types don't require a file on disk.
|
||||
*
|
||||
* Note that we don't check for drop-ins here, because we allow drop-ins for transient units
|
||||
* identically to non-transient units, both unit-specific and hierarchical. E.g. for a-b-c.service:
|
||||
* service.d/….conf, a-.service.d/….conf, a-b-.service.d/….conf, a-b-c.service.d/….conf.
|
||||
*/
|
||||
|
||||
return !(!IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_LOADED) ||
|
||||
u->fragment_path ||
|
||||
u->source_path ||
|
||||
!strv_isempty(u->dropin_paths) ||
|
||||
u->job ||
|
||||
u->merged_into);
|
||||
return IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_LOADED) &&
|
||||
!u->fragment_path &&
|
||||
!u->source_path &&
|
||||
!u->job &&
|
||||
!u->merged_into;
|
||||
}
|
||||
|
||||
pid_t unit_control_pid(Unit *u) {
|
||||
|
||||
+152
-33
@@ -3,30 +3,32 @@
|
||||
set -eux
|
||||
set -o pipefail
|
||||
|
||||
_clear_service () {
|
||||
local SERVICE_NAME="${1:?}"
|
||||
systemctl stop "$SERVICE_NAME.service" 2>/dev/null || :
|
||||
rm -f /{etc,run,usr/lib}/systemd/system/"$SERVICE_NAME".service
|
||||
rm -fr /{etc,run,usr/lib}/systemd/system/"$SERVICE_NAME".service.d
|
||||
rm -fr /{etc,run,usr/lib}/systemd/system/"$SERVICE_NAME".service.{wants,requires}
|
||||
if [[ $SERVICE_NAME == *@ ]]; then
|
||||
systemctl stop "$SERVICE_NAME"*.service 2>/dev/null || :
|
||||
rm -f /{etc,run,usr/lib}/systemd/system/"$SERVICE_NAME"*.service
|
||||
rm -fr /{etc,run,usr/lib}/systemd/system/"$SERVICE_NAME"*.service.d
|
||||
rm -fr /{etc,run,usr/lib}/systemd/system/"$SERVICE_NAME"*.service.{wants,requires}
|
||||
clear_unit () {
|
||||
local UNIT_NAME="${1:?}"
|
||||
systemctl stop "$UNIT_NAME" 2>/dev/null || :
|
||||
rm -f /{etc,run,usr/lib}/systemd/system/"$UNIT_NAME"
|
||||
rm -fr /{etc,run,usr/lib}/systemd/system/"$UNIT_NAME".d
|
||||
rm -fr /{etc,run,usr/lib}/systemd/system/"$UNIT_NAME".{wants,requires}
|
||||
if [[ $UNIT_NAME == *@ ]]; then
|
||||
local base="${UNIT_NAME%@*}"
|
||||
local suffix="${UNIT_NAME##*.}"
|
||||
systemctl stop "$base@"*."$suffix" 2>/dev/null || :
|
||||
rm -f /{etc,run,usr/lib}/systemd/system/"$base@"*."$suffix"
|
||||
rm -fr /{etc,run,usr/lib}/systemd/system/"$base@"*."$suffix".d
|
||||
rm -fr /{etc,run,usr/lib}/systemd/system/"$base@"*."$suffix".{wants,requires}
|
||||
fi
|
||||
}
|
||||
|
||||
clear_services () {
|
||||
clear_units () {
|
||||
for u in "$@"; do
|
||||
_clear_service "$u"
|
||||
clear_unit "$u"
|
||||
done
|
||||
systemctl daemon-reload
|
||||
}
|
||||
|
||||
create_service () {
|
||||
local SERVICE_NAME="${1:?}"
|
||||
clear_services "$SERVICE_NAME"
|
||||
clear_units "${SERVICE_NAME}".service
|
||||
|
||||
cat >/etc/systemd/system/"$SERVICE_NAME".service <<EOF
|
||||
[Unit]
|
||||
@@ -119,7 +121,7 @@ EOF
|
||||
check_ok test15-b ExecCondition "/bin/echo test15-b"
|
||||
rm -rf /usr/lib/systemd/system/service.d
|
||||
|
||||
clear_services test15-a test15-b test15-c test15-c1
|
||||
clear_units test15-{a,b,c,c1}.service
|
||||
}
|
||||
|
||||
test_linked_units () {
|
||||
@@ -146,7 +148,7 @@ test_linked_units () {
|
||||
# Make sure it is completely ignored.
|
||||
|
||||
rm /test15-a@.scope
|
||||
clear_services test15-a test15-b
|
||||
clear_units test15-{a,b}.service
|
||||
}
|
||||
|
||||
test_template_alias() {
|
||||
@@ -172,32 +174,147 @@ test_template_alias() {
|
||||
check_ko test15-b@other Names test15-a@other.service
|
||||
check_ok test15-b@other Names test15-b@other.service
|
||||
|
||||
clear_services test15-a@ test15-b@
|
||||
clear_units test15-{a,b}@.service
|
||||
}
|
||||
|
||||
test_hierarchical_dropins () {
|
||||
echo "Testing hierarchical dropins..."
|
||||
test_hierarchical_service_dropins () {
|
||||
echo "Testing hierarchical service dropins..."
|
||||
echo "*** test service.d/ top level drop-in"
|
||||
create_services a-b-c
|
||||
check_ko a-b-c ExecCondition "/bin/echo service.d"
|
||||
check_ko a-b-c ExecCondition "/bin/echo a-.service.d"
|
||||
check_ko a-b-c ExecCondition "/bin/echo a-b-.service.d"
|
||||
check_ko a-b-c ExecCondition "/bin/echo a-b-c.service.d"
|
||||
check_ko a-b-c ExecCondition "echo service.d"
|
||||
check_ko a-b-c ExecCondition "echo a-.service.d"
|
||||
check_ko a-b-c ExecCondition "echo a-b-.service.d"
|
||||
check_ko a-b-c ExecCondition "echo a-b-c.service.d"
|
||||
|
||||
for dropin in service.d a-.service.d a-b-.service.d a-b-c.service.d; do
|
||||
mkdir -p /usr/lib/systemd/system/$dropin
|
||||
echo "
|
||||
[Service]
|
||||
ExecCondition=/bin/echo $dropin
|
||||
ExecCondition=echo $dropin
|
||||
" >/usr/lib/systemd/system/$dropin/override.conf
|
||||
systemctl daemon-reload
|
||||
check_ok a-b-c ExecCondition "/bin/echo $dropin"
|
||||
check_ok a-b-c ExecCondition "echo $dropin"
|
||||
|
||||
# Check that we can start a transient service in presence of the drop-ins
|
||||
systemd-run -u a-b-c2.service -p Description='sleepy' sleep infinity
|
||||
|
||||
# The transient setting replaces the default
|
||||
check_ok a-b-c2.service Description "sleepy"
|
||||
|
||||
# The override takes precedence for ExecCondition
|
||||
# (except the last iteration when it only applies to the other service)
|
||||
if [ "$dropin" != "a-b-c.service.d" ]; then
|
||||
check_ok a-b-c2.service ExecCondition "echo $dropin"
|
||||
fi
|
||||
|
||||
# Check that things are the same after a reload
|
||||
systemctl daemon-reload
|
||||
check_ok a-b-c2.service Description "sleepy"
|
||||
if [ "$dropin" != "a-b-c.service.d" ]; then
|
||||
check_ok a-b-c2.service ExecCondition "echo $dropin"
|
||||
fi
|
||||
|
||||
systemctl stop a-b-c2.service
|
||||
done
|
||||
for dropin in service.d a-.service.d a-b-.service.d a-b-c.service.d; do
|
||||
rm -rf /usr/lib/systemd/system/$dropin
|
||||
done
|
||||
|
||||
clear_services a-b-c
|
||||
clear_units a-b-c.service
|
||||
}
|
||||
|
||||
test_hierarchical_slice_dropins () {
|
||||
echo "Testing hierarchical slice dropins..."
|
||||
echo "*** test slice.d/ top level drop-in"
|
||||
# Slice units don't even need a fragment, so we test the defaults here
|
||||
check_ok a-b-c.slice Description "Slice /a/b/c"
|
||||
check_ok a-b-c.slice MemoryMax "infinity"
|
||||
|
||||
# Test drop-ins
|
||||
for dropin in slice.d a-.slice.d a-b-.slice.d a-b-c.slice.d; do
|
||||
mkdir -p /usr/lib/systemd/system/$dropin
|
||||
echo "
|
||||
[Slice]
|
||||
MemoryMax=1000000000
|
||||
" >/usr/lib/systemd/system/$dropin/override.conf
|
||||
systemctl daemon-reload
|
||||
check_ok a-b-c.slice MemoryMax "1000000000"
|
||||
|
||||
busctl call \
|
||||
org.freedesktop.systemd1 \
|
||||
/org/freedesktop/systemd1 \
|
||||
org.freedesktop.systemd1.Manager \
|
||||
StartTransientUnit 'ssa(sv)a(sa(sv))' \
|
||||
'a-b-c.slice' 'replace' \
|
||||
2 \
|
||||
'Description' s 'slice too' \
|
||||
'MemoryMax' t 1000000002 \
|
||||
0
|
||||
|
||||
# The override takes precedence for MemoryMax
|
||||
check_ok a-b-c.slice MemoryMax "1000000000"
|
||||
# The transient setting replaces the default
|
||||
check_ok a-b-c.slice Description "slice too"
|
||||
|
||||
# Check that things are the same after a reload
|
||||
systemctl daemon-reload
|
||||
check_ok a-b-c.slice MemoryMax "1000000000"
|
||||
check_ok a-b-c.slice Description "slice too"
|
||||
|
||||
busctl call \
|
||||
org.freedesktop.systemd1 \
|
||||
/org/freedesktop/systemd1 \
|
||||
org.freedesktop.systemd1.Manager \
|
||||
StopUnit 'ss' \
|
||||
'a-b-c.slice' 'replace'
|
||||
|
||||
rm /usr/lib/systemd/system/$dropin/override.conf
|
||||
done
|
||||
|
||||
# Test unit with a fragment
|
||||
echo "
|
||||
[Slice]
|
||||
MemoryMax=1000000001
|
||||
" >/usr/lib/systemd/system/a-b-c.slice
|
||||
systemctl daemon-reload
|
||||
check_ok a-b-c.slice MemoryMax "1000000001"
|
||||
|
||||
clear_units a-b-c.slice
|
||||
}
|
||||
|
||||
test_transient_service_dropins () {
|
||||
echo "Testing dropins for a transient service..."
|
||||
echo "*** test transient service drop-ins"
|
||||
|
||||
mkdir -p /etc/systemd/system/service.d
|
||||
mkdir -p /etc/systemd/system/a-.service.d
|
||||
mkdir -p /etc/systemd/system/a-b-.service.d
|
||||
mkdir -p /etc/systemd/system/a-b-c.service.d
|
||||
|
||||
echo -e '[Service]\nStandardInputText=aaa' >/etc/systemd/system/service.d/drop1.conf
|
||||
echo -e '[Service]\nStandardInputText=bbb' >/etc/systemd/system/a-.service.d/drop2.conf
|
||||
echo -e '[Service]\nStandardInputText=ccc' >/etc/systemd/system/a-b-.service.d/drop3.conf
|
||||
echo -e '[Service]\nStandardInputText=ddd' >/etc/systemd/system/a-b-c.service.d/drop4.conf
|
||||
|
||||
# There's no fragment yet, so this fails
|
||||
systemctl cat a-b-c.service && exit 1
|
||||
|
||||
# xxx → eHh4Cg==
|
||||
systemd-run -u a-b-c.service -p StandardInputData=eHh4Cg== sleep infinity
|
||||
|
||||
data=$(systemctl show -P StandardInputData a-b-c.service)
|
||||
# xxx\naaa\n\bbb\nccc\nddd\n → eHh4…
|
||||
test "$data" = "eHh4CmFhYQpiYmIKY2NjCmRkZAo="
|
||||
|
||||
# Do a reload and check again
|
||||
systemctl daemon-reload
|
||||
data=$(systemctl show -P StandardInputData a-b-c.service)
|
||||
test "$data" = "eHh4CmFhYQpiYmIKY2NjCmRkZAo="
|
||||
|
||||
clear_units a-b-c.service
|
||||
rm /etc/systemd/system/service.d/drop1.conf \
|
||||
/etc/systemd/system/a-.service.d/drop2.conf \
|
||||
/etc/systemd/system/a-b-.service.d/drop3.conf
|
||||
}
|
||||
|
||||
test_template_dropins () {
|
||||
@@ -346,7 +463,7 @@ EOF
|
||||
check_ok bar-alias@3 Requires yup-template-requires.device
|
||||
check_ok bar-alias@3 Requires yup-3-requires.device
|
||||
|
||||
clear_services foo {bar,yup,bar-alias}@{,1,2,3}
|
||||
clear_units foo.service {bar,yup,bar-alias}@{,1,2,3}.service
|
||||
}
|
||||
|
||||
test_alias_dropins () {
|
||||
@@ -361,7 +478,7 @@ test_alias_dropins () {
|
||||
systemctl --quiet is-active test15-b
|
||||
systemctl stop test15-a test15-b
|
||||
rm /etc/systemd/system/test15-b1.service
|
||||
clear_services test15-a test15-b
|
||||
clear_units test15-{a,b}.service
|
||||
|
||||
# Check that dependencies don't vary.
|
||||
echo "*** test 2"
|
||||
@@ -378,7 +495,7 @@ test_alias_dropins () {
|
||||
systemctl stop test15-a test15-x test15-y
|
||||
rm /etc/systemd/system/test15-a1.service
|
||||
|
||||
clear_services test15-a test15-x test15-y
|
||||
clear_units test15-{a,x,y}.service
|
||||
}
|
||||
|
||||
test_masked_dropins () {
|
||||
@@ -499,7 +616,7 @@ EOF
|
||||
ln -sf /dev/null /etc/systemd/system/test15-a.service.requires/test15-b.service
|
||||
check_ok test15-a Requires test15-b
|
||||
|
||||
clear_services test15-a test15-b
|
||||
clear_units test15-{a,b}.service
|
||||
}
|
||||
|
||||
test_invalid_dropins () {
|
||||
@@ -511,7 +628,7 @@ test_invalid_dropins () {
|
||||
# Assertion failed on earlier versions, command exits unsuccessfully on later versions
|
||||
systemctl cat a@.service || true
|
||||
systemctl stop a
|
||||
clear_services a
|
||||
clear_units a.service
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -531,13 +648,15 @@ EOF
|
||||
ln -s /tmp/testsuite-15-test15-a-dropin-directory-regular /usr/lib/systemd/system/test15-a.service.d
|
||||
check_ok test15-a Description hogehoge
|
||||
|
||||
clear_services test15-a
|
||||
clear_units test15-a.service
|
||||
}
|
||||
|
||||
test_basic_dropins
|
||||
test_linked_units
|
||||
test_template_alias
|
||||
test_hierarchical_dropins
|
||||
test_hierarchical_service_dropins
|
||||
test_hierarchical_slice_dropins
|
||||
test_transient_service_dropins
|
||||
test_template_dropins
|
||||
test_alias_dropins
|
||||
test_masked_dropins
|
||||
|
||||
Reference in New Issue
Block a user