From dbfc8cccda1526bd162827e216badf29375f3293 Mon Sep 17 00:00:00 2001 From: Ygal Blum Date: Fri, 1 Nov 2024 15:33:23 -0400 Subject: [PATCH] Quadlet - support image file based mount in container file Signed-off-by: Ygal Blum --- docs/source/markdown/podman-systemd.unit.5.md | 9 +++--- pkg/systemd/quadlet/quadlet.go | 28 +++++++++++-------- test/e2e/quadlet/mount.container | 6 ++-- test/e2e/quadlet_test.go | 2 +- 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/docs/source/markdown/podman-systemd.unit.5.md b/docs/source/markdown/podman-systemd.unit.5.md index e2cafd9b55..80d4351652 100644 --- a/docs/source/markdown/podman-systemd.unit.5.md +++ b/docs/source/markdown/podman-systemd.unit.5.md @@ -657,10 +657,11 @@ Attach a filesystem mount to the container. This is equivalent to the Podman `--mount` option, and generally has the form `type=TYPE,TYPE-SPECIFIC-OPTION[,...]`. -As a special case, for `type=volume` if `source` ends with `.volume`, a Podman named volume called -`systemd-$name` is used as the source, and the generated systemd service contains -a dependency on the `$name-volume.service`. Such a volume can be automatically be lazily -created by using a `$name.volume` Quadlet file. +There are two special cases. +1. For `type=volume`, if `source` ends with `.volume`, the Podman named volume generated by the corresponding `.volume` file is used. +2. For `type=image`, if `source` ends with `.image`, the image generated by the corresponding `.image` file is used. + +In both cases, the generated systemd service will contain a dependency on the service generated for the corresponding unit. This key can be listed multiple times. diff --git a/pkg/systemd/quadlet/quadlet.go b/pkg/systemd/quadlet/quadlet.go index 3e957200de..ff0a157e6f 100644 --- a/pkg/systemd/quadlet/quadlet.go +++ b/pkg/systemd/quadlet/quadlet.go @@ -1874,7 +1874,7 @@ func handleLogOpt(unitFile *parser.UnitFile, groupName string, podman *PodmanCmd } } -func handleStorageSource(quadletUnitFile, serviceUnitFile *parser.UnitFile, source string, unitsInfoMap map[string]*UnitInfo) (string, error) { +func handleStorageSource(quadletUnitFile, serviceUnitFile *parser.UnitFile, source string, unitsInfoMap map[string]*UnitInfo, checkImage bool) (string, error) { if source[0] == '.' { var err error source, err = getAbsolutePath(quadletUnitFile, source) @@ -1885,18 +1885,18 @@ func handleStorageSource(quadletUnitFile, serviceUnitFile *parser.UnitFile, sour if source[0] == '/' { // Absolute path serviceUnitFile.Add(UnitGroup, "RequiresMountsFor", source) - } else if strings.HasSuffix(source, ".volume") { - volumeUnitInfo, ok := unitsInfoMap[source] + } else if strings.HasSuffix(source, ".volume") || (checkImage && strings.HasSuffix(source, ".image")) { + sourceUnitInfo, ok := unitsInfoMap[source] if !ok { - return "", fmt.Errorf("requested Quadlet image %s was not found", source) + return "", fmt.Errorf("requested Quadlet source %s was not found", source) } // the systemd unit name is $serviceName.service - volumeServiceName := volumeUnitInfo.ServiceFileName() - serviceUnitFile.Add(UnitGroup, "Requires", volumeServiceName) - serviceUnitFile.Add(UnitGroup, "After", volumeServiceName) + sourceServiceName := sourceUnitInfo.ServiceFileName() + serviceUnitFile.Add(UnitGroup, "Requires", sourceServiceName) + serviceUnitFile.Add(UnitGroup, "After", sourceServiceName) - source = volumeUnitInfo.ResourceName + source = sourceUnitInfo.ResourceName } return source, nil @@ -2053,7 +2053,13 @@ func resolveContainerMountParams(containerUnitFile, serviceUnitFile *parser.Unit } // Source resolution is required only for these types of mounts - if !(mountType == "volume" || mountType == "bind" || mountType == "glob") { + sourceResultionRequired := map[string]struct{}{ + "volume": {}, + "bind": {}, + "glob": {}, + "image": {}, + } + if _, ok := sourceResultionRequired[mountType]; !ok { return mount, nil } @@ -2070,7 +2076,7 @@ func resolveContainerMountParams(containerUnitFile, serviceUnitFile *parser.Unit } } - resolvedSource, err := handleStorageSource(containerUnitFile, serviceUnitFile, originalSource, unitsInfoMap) + resolvedSource, err := handleStorageSource(containerUnitFile, serviceUnitFile, originalSource, unitsInfoMap, true) if err != nil { return "", err } @@ -2158,7 +2164,7 @@ func addVolumes(quadletUnitFile, serviceUnitFile *parser.UnitFile, groupName str if source != "" { var err error - source, err = handleStorageSource(quadletUnitFile, serviceUnitFile, source, unitsInfoMap) + source, err = handleStorageSource(quadletUnitFile, serviceUnitFile, source, unitsInfoMap, false) if err != nil { return err } diff --git a/test/e2e/quadlet/mount.container b/test/e2e/quadlet/mount.container index 615fe58631..0f431c1ee2 100644 --- a/test/e2e/quadlet/mount.container +++ b/test/e2e/quadlet/mount.container @@ -9,13 +9,15 @@ Mount=type=bind,src=/path/on/host,dst=/path/in/container,relabel=shared,U=true ## assert-podman-args-key-val "--mount" "," "type=volume,source=vol1,destination=/path/in/container,ro=true" Mount=type=volume,source=vol1,destination=/path/in/container,ro=true ## assert-podman-args-key-val "--mount" "," "type=volume,source=systemd-basic,destination=/path/in/container,ro=true" -## assert-key-is "Unit" "Requires" "basic-volume.service" -## assert-key-is-regex "Unit" "After" "network-online.target|podman-user-wait-network-online.service" "basic-volume.service" +## assert-key-is "Unit" "Requires" "basic-volume.service" "basic-image.service" +## assert-key-is-regex "Unit" "After" "network-online.target|podman-user-wait-network-online.service" "basic-volume.service" "basic-image.service" Mount=type=volume,source=basic.volume,destination=/path/in/container,ro=true ## assert-podman-args-key-val "--mount" "," "type=tmpfs,tmpfs-size=512M,destination=/path/in/container" Mount=type=tmpfs,tmpfs-size=512M,destination=/path/in/container ## assert-podman-args-key-val "--mount" "," "type=image,source=fedora,destination=/fedora-image,rw=true" Mount=type=image,source=fedora,destination=/fedora-image,rw=true +## assert-podman-args-key-val "--mount" "," "type=image,source=localhost/imagename,destination=/fedora-image,rw=true" +Mount=type=image,source=basic.image,destination=/fedora-image,rw=true ## assert-podman-args-key-val "--mount" "," "type=devpts,destination=/dev/pts" Mount=type=devpts,destination=/dev/pts ## assert-podman-args-key-val-regex "--mount" "," "type=bind,source=.*/podman-e2e-.*/subtest-.*/quadlet/path/on/host,destination=/path/in/container" diff --git a/test/e2e/quadlet_test.go b/test/e2e/quadlet_test.go index ffed49a8a2..2238adc3ce 100644 --- a/test/e2e/quadlet_test.go +++ b/test/e2e/quadlet_test.go @@ -1094,7 +1094,7 @@ BOGUS=foo runSuccessQuadletTestCase(fileName) }, - Entry("Container - Mount", "mount.container", []string{"basic.volume"}), + Entry("Container - Mount", "mount.container", []string{"basic.image", "basic.volume"}), Entry("Container - Quadlet Network", "network.quadlet.container", []string{"basic.network"}), Entry("Container - Quadlet Volume", "volume.container", []string{"basic.volume"}), Entry("Container - Mount overriding service name", "mount.servicename.container", []string{"service-name.volume"}),