1
0
mirror of https://github.com/containers/podman.git synced 2026-02-05 15:45:08 +01:00

Merge pull request #27169 from ygalblum/quadlet-template-dependency

Quadlet - Support template dependency
This commit is contained in:
openshift-merge-bot[bot]
2025-10-03 15:51:31 +00:00
committed by GitHub
7 changed files with 162 additions and 13 deletions

View File

@@ -908,6 +908,19 @@ func getContainerName(container *parser.UnitFile) string {
return containerName
}
// Get the unresolved resource name that may contain '%'.
func getResourceName(unit *parser.UnitFile, group, key string) string {
resourceName, ok := unit.Lookup(group, key)
if !ok || len(resourceName) == 0 {
resourceName = removeExtension(unit.Filename, "systemd-", "")
// By default, We want to name the resource by the service name.
if strings.Contains(unit.Filename, "@") {
resourceName = resourceName[:len(resourceName)-1] + "-%i"
}
}
return resourceName
}
// Get the resolved container name that contains no '%'.
// Returns an empty string if not resolvable.
func GetContainerResourceName(container *parser.UnitFile) string {
@@ -954,10 +967,7 @@ func ConvertNetwork(network *parser.UnitFile, name string, unitsInfoMap map[stri
}
// Derive network name from unit name (with added prefix), or use user-provided name.
networkName, ok := network.Lookup(NetworkGroup, KeyNetworkName)
if !ok || len(networkName) == 0 {
networkName = removeExtension(name, "systemd-", "")
}
networkName := getResourceName(network, NetworkGroup, KeyNetworkName)
if network.LookupBooleanWithDefault(NetworkGroup, KeyNetworkDeleteOnStop, false) {
serviceStopPostCmd := createBasePodmanCommand(network, NetworkGroup)
@@ -1046,10 +1056,7 @@ func ConvertVolume(volume *parser.UnitFile, name string, unitsInfoMap map[string
}
// Derive volume name from unit name (with added prefix), or use user-provided name.
volumeName, ok := volume.Lookup(VolumeGroup, KeyVolumeName)
if !ok || len(volumeName) == 0 {
volumeName = removeExtension(name, "systemd-", "")
}
volumeName := getResourceName(volume, VolumeGroup, KeyVolumeName)
podman := createBasePodmanCommand(volume, VolumeGroup)
@@ -1503,7 +1510,12 @@ func getServiceName(quadletUnitFile *parser.UnitFile, groupName string, defaultE
if serviceName, ok := quadletUnitFile.Lookup(groupName, KeyServiceName); ok {
return serviceName
}
return removeExtension(quadletUnitFile.Filename, "", defaultExtraSuffix)
baseServiceName := removeExtension(quadletUnitFile.Filename, "", "")
if baseServiceName[len(baseServiceName)-1] == '@' {
baseServiceName = baseServiceName[:len(baseServiceName)-1]
defaultExtraSuffix += "@"
}
return baseServiceName + defaultExtraSuffix
}
func GetPodResourceName(podUnit *parser.UnitFile) string {

View File

@@ -0,0 +1,10 @@
## assert-podman-args-key-val "--mount" "," "type=volume,source=systemd-template-dependency-%i,destination=/path/in/container,ro=true"
## assert-podman-args -v systemd-template-dependency-%i:/container/quadlet
## assert-podman-args "--network" "systemd-template-dependency-%i"
## assert-key-is "Unit" "Requires" "template-dependency-network@.service" "template-dependency-volume@.service" "template-dependency-volume@.service"
[Container]
Image=localhost/imagename
Mount=type=volume,source=template-dependency@.volume,destination=/path/in/container,ro=true
Volume=template-dependency@.volume:/container/quadlet
Network=template-dependency@.network

View File

@@ -0,0 +1 @@
[Network]

View File

@@ -0,0 +1 @@
[Volume]

View File

@@ -1195,6 +1195,14 @@ BOGUS=foo
"basic.volume",
},
),
Entry(
"Container - Template with Volume Template dependency",
"template-dependency@.container",
[]string{
"template-dependency@.volume",
"template-dependency@.network",
},
),
Entry("Volume - Quadlet image (.build)", "build.quadlet.volume", []string{"basic.build"}),
Entry("Volume - Quadlet image (.image)", "image.quadlet.volume", []string{"basic.image"}),

View File

@@ -11,6 +11,7 @@ load helpers.registry
load helpers.systemd
UNIT_FILES=()
SERVICES_TO_STOP=()
function start_time() {
sleep_to_next_second # Ensure we're on a new second with no previous logging
@@ -26,16 +27,32 @@ function setup() {
start_time
# Clear arrays for each test
SERVICES_TO_STOP=()
basic_setup
}
function teardown() {
# Stop manually specified services
for service in ${SERVICES_TO_STOP[@]}; do
run systemctl stop "$service"
if [ $status -ne 0 ]; then
echo "# WARNING: systemctl stop failed in teardown: $output" >&3
fi
run systemctl reset-failed "$service"
done
for UNIT_FILE in ${UNIT_FILES[@]}; do
if [[ -e "$UNIT_FILE" ]]; then
local service=$(basename "$UNIT_FILE")
run systemctl stop "$service"
if [ $status -ne 0 ]; then
echo "# WARNING: systemctl stop failed in teardown: $output" >&3
# Skip stopping template services (those ending with '@')
# as they cannot be stopped directly without an instance name
if [[ ! "$service" =~ @\.service$ ]]; then
run systemctl stop "$service"
if [ $status -ne 0 ]; then
echo "# WARNING: systemctl stop failed in teardown: $output" >&3
fi
fi
run systemctl reset-failed "$service"
rm -f "$UNIT_FILE"
@@ -437,6 +454,99 @@ EOF
run_podman volume rm $volume_name
}
# A quadlet container template depends on a quadlet volume and network templates
@test "quadlet - template dependency" {
# Save the unit name to use as the volume template for the container template
local quadlet_vol_unit=dep_$(safename)@.volume
local quadlet_vol_file=$PODMAN_TMPDIR/${quadlet_vol_unit}
cat > $quadlet_vol_file <<EOF
[Volume]
EOF
local quadlet_tmpdir=$(mktemp -d --tmpdir=$PODMAN_TMPDIR quadlet.XXXXXX)
# Have quadlet create the systemd unit file for the volume template unit
run_quadlet "$quadlet_vol_file" "$quadlet_tmpdir"
# Save the volume service name since the variable will be overwritten
local vol_service=$QUADLET_SERVICE_NAME
local volume_name=systemd-$(basename $quadlet_vol_file .volume)
# For template units, the volume name should have -%i appended
volume_name=${volume_name%@}-%i
# Save the unit name to use as the network template for the container template
local quadlet_net_unit=dep_$(safename)@.network
local quadlet_net_file=$PODMAN_TMPDIR/${quadlet_net_unit}
cat > $quadlet_net_file <<EOF
[Network]
EOF
# Have quadlet create the systemd unit file for the network template unit
run_quadlet "$quadlet_net_file" "$quadlet_tmpdir"
# Save the network service name since the variable will be overwritten
local net_service=$QUADLET_SERVICE_NAME
local network_name=systemd-$(basename $quadlet_net_file .network)
# For template units, the network name should have -%i appended
network_name=${network_name%@}-%i
local quadlet_file=$PODMAN_TMPDIR/user_$(safename)@.container
cat > $quadlet_file <<EOF
[Container]
Image=$IMAGE
Exec=top
Volume=$quadlet_vol_unit:/tmp
Network=$quadlet_net_unit
EOF
# Have quadlet create the systemd unit file for the container template unit
run_quadlet "$quadlet_file" "$quadlet_tmpdir"
# Save the container service name for readability
local container_service=$QUADLET_SERVICE_NAME
# Create instance names for the template units
local instance_name="test"
local vol_service_instance="${vol_service%@*}@${instance_name}.service"
local net_service_instance="${net_service%@*}@${instance_name}.service"
local container_service_instance="${container_service%@*}@${instance_name}.service"
local volume_name_instance="systemd-dep_$(safename)-${instance_name}"
local network_name_instance="systemd-dep_$(safename)-${instance_name}"
# Volume should not exist
run_podman 1 volume exists ${volume_name_instance}
# Network should not exist
run_podman 1 network exists ${network_name_instance}
# Start the container service instance which should also trigger the start of the volume service instance
service_setup $container_service_instance
# Add the service instances to SERVICES_TO_STOP for proper cleanup
# SERVICES_TO_STOP+=("$container_service_instance")
SERVICES_TO_STOP+=("$vol_service_instance")
SERVICES_TO_STOP+=("$net_service_instance")
# Volume system unit instance should be active
run systemctl show --property=ActiveState "$vol_service_instance"
assert "$output" = "ActiveState=active" \
"volume template instance should be active via dependency"
# Network system unit instance should be active
run systemctl show --property=ActiveState "$net_service_instance"
assert "$output" = "ActiveState=active" \
"network template instance should be active via dependency"
# Volume should exist
run_podman volume exists ${volume_name_instance}
# Network should exist
run_podman network exists ${network_name_instance}
# Clean up the created resources
service_cleanup $container_service_instance failed
run_podman volume rm $volume_name_instance
run_podman network rm $network_name_instance
}
# A quadlet container depends on a named quadlet volume
@test "quadlet - named volume dependency" {
local volume_name="v-$(safename)"

View File

@@ -115,6 +115,13 @@ quadlet_to_service_name() {
local extension="${filename##*.}"
local filename="${filename%.*}"
local suffix=""
local is_template=""
# Check if this is a template unit (ends with @)
if [[ "$filename" == *@ ]]; then
is_template="@"
filename="${filename%@}"
fi
if [ "$extension" == "volume" ]; then
suffix="-volume"
@@ -128,5 +135,5 @@ quadlet_to_service_name() {
suffix="-build"
fi
echo "$filename$suffix.service"
echo "$filename$suffix$is_template.service"
}