diff --git a/pkg/systemd/quadlet/quadlet.go b/pkg/systemd/quadlet/quadlet.go index 575abe07744..45722f51e0d 100644 --- a/pkg/systemd/quadlet/quadlet.go +++ b/pkg/systemd/quadlet/quadlet.go @@ -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 { diff --git a/test/e2e/quadlet/template-dependency@.container b/test/e2e/quadlet/template-dependency@.container new file mode 100644 index 00000000000..be6356ef03c --- /dev/null +++ b/test/e2e/quadlet/template-dependency@.container @@ -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 diff --git a/test/e2e/quadlet/template-dependency@.network b/test/e2e/quadlet/template-dependency@.network new file mode 100644 index 00000000000..264f70a03aa --- /dev/null +++ b/test/e2e/quadlet/template-dependency@.network @@ -0,0 +1 @@ +[Network] diff --git a/test/e2e/quadlet/template-dependency@.volume b/test/e2e/quadlet/template-dependency@.volume new file mode 100644 index 00000000000..4fd65347844 --- /dev/null +++ b/test/e2e/quadlet/template-dependency@.volume @@ -0,0 +1 @@ +[Volume] diff --git a/test/e2e/quadlet_test.go b/test/e2e/quadlet_test.go index 7aaf5f646e1..44dad370d55 100644 --- a/test/e2e/quadlet_test.go +++ b/test/e2e/quadlet_test.go @@ -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"}), diff --git a/test/system/252-quadlet.bats b/test/system/252-quadlet.bats index 85b6e942ebc..ad19a86e86d 100644 --- a/test/system/252-quadlet.bats +++ b/test/system/252-quadlet.bats @@ -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 < $quadlet_net_file < $quadlet_file <