Merge pull request #27385 from KonishchevDmitry/bind-mounts-with-spaces

Escape RequiresMountsFor value to properly handle bind mounts with spaces in path
This commit is contained in:
openshift-merge-bot[bot]
2025-10-28 13:22:03 +00:00
committed by GitHub
13 changed files with 61 additions and 35 deletions

View File

@@ -879,6 +879,15 @@ func (f *UnitFile) Add(groupName string, key string, value string) {
group.add(key, value) group.add(key, value)
} }
func (f *UnitFile) AddEscaped(groupName string, key string, value string) {
if wordNeedEscape(value) {
var escaped strings.Builder
appendEscapeWord(&escaped, value)
value = escaped.String()
}
f.Add(groupName, key, value)
}
func (f *UnitFile) AddCmdline(groupName string, key string, args []string) { func (f *UnitFile) AddCmdline(groupName string, key string, args []string) {
f.Add(groupName, key, escapeWords(args)) f.Add(groupName, key, escapeWords(args))
} }

View File

@@ -1151,7 +1151,7 @@ func ConvertVolume(volume *parser.UnitFile, unitsInfoMap map[string]*UnitInfo, i
if devValid { if devValid {
podman.add("--opt", fmt.Sprintf("type=%s", devType)) podman.add("--opt", fmt.Sprintf("type=%s", devType))
if devType == "bind" { if devType == "bind" {
service.Add(UnitGroup, "RequiresMountsFor", dev) service.AddEscaped(UnitGroup, "RequiresMountsFor", dev)
} }
} else { } else {
return nil, warnings, fmt.Errorf("key Type can't be used without Device") return nil, warnings, fmt.Errorf("key Type can't be used without Device")
@@ -1929,7 +1929,7 @@ func handleStorageSource(quadletUnitFile, serviceUnitFile *parser.UnitFile, sour
} }
if source[0] == '/' { if source[0] == '/' {
// Absolute path // Absolute path
serviceUnitFile.Add(UnitGroup, "RequiresMountsFor", source) serviceUnitFile.AddEscaped(UnitGroup, "RequiresMountsFor", source)
} else if strings.HasSuffix(source, ".volume") || (checkImage && strings.HasSuffix(source, ".image")) || strings.HasSuffix(source, ".artifact") { } else if strings.HasSuffix(source, ".volume") || (checkImage && strings.HasSuffix(source, ".image")) || strings.HasSuffix(source, ".artifact") {
sourceUnitInfo, ok := unitsInfoMap[source] sourceUnitInfo, ok := unitsInfoMap[source]
if !ok { if !ok {

View File

@@ -1,7 +1,7 @@
## assert-key-contains Service ExecStart " --opt type=bind " ## assert-last-key-contains Service ExecStart " --opt type=bind "
## assert-key-contains Service ExecStart " --opt device=/var/lib/data " ## assert-last-key-contains Service ExecStart " --opt device=/var/lib/data "
## assert-key-contains Service ExecStart " --opt nocopy " ## assert-last-key-contains Service ExecStart " --opt nocopy "
## assert-key-contains Unit RequiresMountsFor "/var/lib/data" ## assert-last-key-contains Unit RequiresMountsFor "/var/lib/data"
[Volume] [Volume]
Device=/var/lib/data Device=/var/lib/data

View File

@@ -1,7 +1,7 @@
## assert-key-contains Service ExecStart " --opt o=uid=0,gid=11,rw,compress=zstd " ## assert-last-key-contains Service ExecStart " --opt o=uid=0,gid=11,rw,compress=zstd "
## assert-key-contains Service ExecStart " --opt type=btrfs " ## assert-last-key-contains Service ExecStart " --opt type=btrfs "
## assert-key-contains Service ExecStart " --opt device=/dev/vda1 " ## assert-last-key-contains Service ExecStart " --opt device=/dev/vda1 "
## assert-key-contains Service ExecStart " --opt copy " ## assert-last-key-contains Service ExecStart " --opt copy "
[Volume] [Volume]
# Test usernames too # Test usernames too

View File

@@ -1,7 +1,7 @@
## assert-key-contains Service ExecStart " --opt o=uid=0,gid=11,rw,compress=zstd " ## assert-last-key-contains Service ExecStart " --opt o=uid=0,gid=11,rw,compress=zstd "
## assert-key-contains Service ExecStart " --opt type=btrfs " ## assert-last-key-contains Service ExecStart " --opt type=btrfs "
## assert-key-contains Service ExecStart " --opt device=/dev/vda1 " ## assert-last-key-contains Service ExecStart " --opt device=/dev/vda1 "
## assert-key-contains Service ExecStart " --opt nocopy " ## assert-last-key-contains Service ExecStart " --opt nocopy "
[Volume] [Volume]
# Test usernames too # Test usernames too

View File

@@ -2,7 +2,7 @@
## assert-podman-args "--ipv6" ## assert-podman-args "--ipv6"
## assert-key-is Service Type exec ## assert-key-is Service Type exec
## assert-key-is Service RemainAfterExit no ## assert-key-is Service RemainAfterExit no
## assert-key-contains Service SyslogIdentifier "Modify %N" ## assert-last-key-contains Service SyslogIdentifier "Modify %N"
[Network] [Network]
IPv6=yes IPv6=yes

View File

@@ -1,6 +1,6 @@
## assert-key-contains Service ExecStart " --label org.foo.Arg1=arg1 " ## assert-last-key-contains Service ExecStart " --label org.foo.Arg1=arg1 "
## assert-key-contains Service ExecStart " --label org.foo.Arg2=arg2 " ## assert-last-key-contains Service ExecStart " --label org.foo.Arg2=arg2 "
## assert-key-contains Service ExecStart " --label org.foo.Arg3=arg3 " ## assert-last-key-contains Service ExecStart " --label org.foo.Arg3=arg3 "
[Volume] [Volume]
Label=org.foo.Arg1=arg1 Label=org.foo.Arg1=arg1

View File

@@ -1,7 +1,11 @@
[Container] [Container]
Image=localhost/imagename Image=localhost/imagename
## assert-has-key Unit RequiresMountsFor "/path/on/host"
## assert-podman-args-key-val "--mount" "," "type=bind,source=/path/on/host,destination=/path/in/container" ## assert-podman-args-key-val "--mount" "," "type=bind,source=/path/on/host,destination=/path/in/container"
Mount=type=bind,source=/path/on/host,destination=/path/in/container Mount=type=bind,source=/path/on/host,destination=/path/in/container
## assert-has-key Unit RequiresMountsFor "\"/path/on/host\\x20with\\x20spaces\""
## assert-podman-args-key-val "--mount" "," "type=bind,source=/path/on/host with spaces,dst=/path"
Mount="type=bind,src=/path/on/host with spaces,dst=/path"
## assert-podman-args-key-val "--mount" "," "type=bind,source=/path/on/host,dst=/path/in/container,relabel=shared" ## assert-podman-args-key-val "--mount" "," "type=bind,source=/path/on/host,dst=/path/in/container,relabel=shared"
Mount=type=bind,src=/path/on/host,dst=/path/in/container,relabel=shared Mount=type=bind,src=/path/on/host,dst=/path/in/container,relabel=shared
## assert-podman-args-key-val "--mount" "," "type=bind,source=/path/on/host,dst=/path/in/container,relabel=shared,U=true" ## assert-podman-args-key-val "--mount" "," "type=bind,source=/path/on/host,dst=/path/in/container,relabel=shared,U=true"

View File

@@ -1,7 +1,7 @@
## assert-key-contains "Unit" "Wants" "startwithpod_yes.service" ## assert-last-key-contains "Unit" "Wants" "startwithpod_yes.service"
## assert-key-contains "Unit" "Before" "startwithpod_yes.service" ## assert-last-key-contains "Unit" "Before" "startwithpod_yes.service"
## assert-key-not-contains "Unit" "Wants" "startwithpod_no.service" ## assert-last-key-not-contains "Unit" "Wants" "startwithpod_no.service"
## assert-key-not-contains "Unit" "Before" "startwithpod_no.service" ## assert-last-key-not-contains "Unit" "Before" "startwithpod_no.service"
[Pod] [Pod]

View File

@@ -1,5 +1,5 @@
# assert-key-contains "Unit" "After" "startwithpod-pod.service" # assert-last-key-contains "Unit" "After" "startwithpod-pod.service"
# assert-key-contains "Unit" "BindsTo" "startwithpod-pod.service" # assert-last-key-contains "Unit" "BindsTo" "startwithpod-pod.service"
[Container] [Container]
Image=localhost/image Image=localhost/image

View File

@@ -1,5 +1,5 @@
# assert-key-contains "Unit" "After" "startwithpod-pod.service" # assert-last-key-contains "Unit" "After" "startwithpod-pod.service"
# assert-key-contains "Unit" "BindsTo" "startwithpod-pod.service" # assert-last-key-contains "Unit" "BindsTo" "startwithpod-pod.service"
[Container] [Container]
Image=localhost/image Image=localhost/image

View File

@@ -1,7 +1,7 @@
## assert-key-contains Service ExecStart " --opt o=uid=0,gid=11 " ## assert-last-key-contains Service ExecStart " --opt o=uid=0,gid=11 "
## assert-key-is Service Type oneshot ## assert-key-is Service Type oneshot
## assert-key-is Service RemainAfterExit no ## assert-key-is Service RemainAfterExit no
## assert-key-contains Service SyslogIdentifier "Modify %N" ## assert-last-key-contains Service SyslogIdentifier "Modify %N"
[Volume] [Volume]
# Test usernames too # Test usernames too

View File

@@ -9,6 +9,7 @@ import (
"path/filepath" "path/filepath"
"reflect" "reflect"
"regexp" "regexp"
"slices"
"strings" "strings"
"github.com/containers/podman/v6/pkg/systemd/parser" "github.com/containers/podman/v6/pkg/systemd/parser"
@@ -172,6 +173,16 @@ func (t *quadletTestcase) assertKeyIs(args []string, unit *parser.UnitFile) bool
return true return true
} }
func (t *quadletTestcase) assertHasKey(args []string, unit *parser.UnitFile) bool {
Expect(args).To(HaveLen(3))
group := args[0]
key := args[1]
value := args[2]
realValues := unit.LookupAll(group, key)
return slices.Contains(realValues, value)
}
func (t *quadletTestcase) assertKeyIsEmpty(args []string, unit *parser.UnitFile) bool { func (t *quadletTestcase) assertKeyIsEmpty(args []string, unit *parser.UnitFile) bool {
Expect(args).To(HaveLen(2)) Expect(args).To(HaveLen(2))
group := args[0] group := args[0]
@@ -219,7 +230,7 @@ func (t *quadletTestcase) assertLastKeyIsRegex(args []string, unit *parser.UnitF
return true return true
} }
func (t *quadletTestcase) assertKeyContains(args []string, unit *parser.UnitFile) bool { func (t *quadletTestcase) assertLastKeyContains(args []string, unit *parser.UnitFile) bool {
Expect(args).To(HaveLen(3)) Expect(args).To(HaveLen(3))
group := args[0] group := args[0]
key := args[1] key := args[1]
@@ -229,8 +240,8 @@ func (t *quadletTestcase) assertKeyContains(args []string, unit *parser.UnitFile
return ok && strings.Contains(realValue, value) return ok && strings.Contains(realValue, value)
} }
func (t *quadletTestcase) assertKeyNotContains(args []string, unit *parser.UnitFile) bool { func (t *quadletTestcase) assertLastKeyNotContains(args []string, unit *parser.UnitFile) bool {
return !t.assertKeyContains(args, unit) return !t.assertLastKeyContains(args, unit)
} }
func (t *quadletTestcase) assertPodmanArgs(args []string, unit *parser.UnitFile, key string, allowRegex, globalOnly bool) bool { func (t *quadletTestcase) assertPodmanArgs(args []string, unit *parser.UnitFile, key string, allowRegex, globalOnly bool) bool {
@@ -540,14 +551,16 @@ func (t *quadletTestcase) doAssert(check []string, unit *parser.UnitFile, sessio
ok = t.assertStdErrContains(args, session) ok = t.assertStdErrContains(args, session)
case "assert-key-is": case "assert-key-is":
ok = t.assertKeyIs(args, unit) ok = t.assertKeyIs(args, unit)
case "assert-has-key":
ok = t.assertHasKey(args, unit)
case "assert-key-is-empty": case "assert-key-is-empty":
ok = t.assertKeyIsEmpty(args, unit) ok = t.assertKeyIsEmpty(args, unit)
case "assert-key-is-regex": case "assert-key-is-regex":
ok = t.assertKeyIsRegex(args, unit) ok = t.assertKeyIsRegex(args, unit)
case "assert-key-contains": case "assert-last-key-contains":
ok = t.assertKeyContains(args, unit) ok = t.assertLastKeyContains(args, unit)
case "assert-key-not-contains": case "assert-last-key-not-contains":
ok = t.assertKeyNotContains(args, unit) ok = t.assertLastKeyNotContains(args, unit)
case "assert-last-key-is-regex": case "assert-last-key-is-regex":
ok = t.assertLastKeyIsRegex(args, unit) ok = t.assertLastKeyIsRegex(args, unit)
case "assert-podman-args": case "assert-podman-args":