mirror of
https://github.com/containers/podman.git
synced 2025-07-30 11:52:47 +08:00
Merge pull request #17857 from ygalblum/quadlet-relative-volume
Quadlet - add support for relative path in Volume key in .container file
This commit is contained in:
docs/source/markdown
pkg/systemd/quadlet
test/e2e
@ -467,6 +467,8 @@ If enabled, the container will have a fresh tmpfs mounted on `/tmp`.
|
|||||||
Mount a volume in the container. This is equivalent to the Podman `--volume` option, and
|
Mount a volume in the container. This is equivalent to the Podman `--volume` option, and
|
||||||
generally has the form `[[SOURCE-VOLUME|HOST-DIR:]CONTAINER-DIR[:OPTIONS]]`.
|
generally has the form `[[SOURCE-VOLUME|HOST-DIR:]CONTAINER-DIR[:OPTIONS]]`.
|
||||||
|
|
||||||
|
If `SOURCE-VOLUME` starts with `.`, Quadlet will resolve the path relative to the location of the unit file.
|
||||||
|
|
||||||
As a special case, if `SOURCE-VOLUME` ends with `.volume`, a Podman named volume called
|
As a special case, if `SOURCE-VOLUME` ends with `.volume`, a Podman named volume called
|
||||||
`systemd-$name` will be used as the source, and the generated systemd service will contain
|
`systemd-$name` will be used as the source, and the generated systemd service will contain
|
||||||
a dependency on the `$name-volume.service`. Such a volume can be automatically be lazily
|
a dependency on the `$name-volume.service`. Such a volume can be automatically be lazily
|
||||||
|
@ -492,7 +492,11 @@ func ConvertContainer(container *parser.UnitFile, isUser bool) (*parser.UnitFile
|
|||||||
}
|
}
|
||||||
|
|
||||||
if source != "" {
|
if source != "" {
|
||||||
source = handleStorageSource(service, source)
|
var err error
|
||||||
|
source, err = handleStorageSource(container, service, source)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
podman.add("-v")
|
podman.add("-v")
|
||||||
@ -564,10 +568,14 @@ func ConvertContainer(container *parser.UnitFile, isUser bool) (*parser.UnitFile
|
|||||||
}
|
}
|
||||||
if paramType, ok := paramsMap["type"]; ok {
|
if paramType, ok := paramsMap["type"]; ok {
|
||||||
if paramType == "volume" || paramType == "bind" {
|
if paramType == "volume" || paramType == "bind" {
|
||||||
|
var err error
|
||||||
if paramSource, ok := paramsMap["source"]; ok {
|
if paramSource, ok := paramsMap["source"]; ok {
|
||||||
paramsMap["source"] = handleStorageSource(service, paramSource)
|
paramsMap["source"], err = handleStorageSource(container, service, paramSource)
|
||||||
} else if paramSource, ok = paramsMap["src"]; ok {
|
} else if paramSource, ok = paramsMap["src"]; ok {
|
||||||
paramsMap["src"] = handleStorageSource(service, paramSource)
|
paramsMap["src"], err = handleStorageSource(container, service, paramSource)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1047,10 +1055,17 @@ func handleLogDriver(unitFile *parser.UnitFile, groupName string, podman *Podman
|
|||||||
podman.add("--log-driver", logDriver)
|
podman.add("--log-driver", logDriver)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleStorageSource(unitFile *parser.UnitFile, source string) string {
|
func handleStorageSource(quadletUnitFile, serviceUnitFile *parser.UnitFile, source string) (string, error) {
|
||||||
|
if source[0] == '.' {
|
||||||
|
var err error
|
||||||
|
source, err = getAbsolutePath(quadletUnitFile, source)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
if source[0] == '/' {
|
if source[0] == '/' {
|
||||||
// Absolute path
|
// Absolute path
|
||||||
unitFile.Add(UnitGroup, "RequiresMountsFor", source)
|
serviceUnitFile.Add(UnitGroup, "RequiresMountsFor", source)
|
||||||
} else if strings.HasSuffix(source, ".volume") {
|
} else if strings.HasSuffix(source, ".volume") {
|
||||||
// the podman volume name is systemd-$name
|
// the podman volume name is systemd-$name
|
||||||
volumeName := replaceExtension(source, "", "systemd-", "")
|
volumeName := replaceExtension(source, "", "systemd-", "")
|
||||||
@ -1060,11 +1075,11 @@ func handleStorageSource(unitFile *parser.UnitFile, source string) string {
|
|||||||
|
|
||||||
source = volumeName
|
source = volumeName
|
||||||
|
|
||||||
unitFile.Add(UnitGroup, "Requires", volumeServiceName)
|
serviceUnitFile.Add(UnitGroup, "Requires", volumeServiceName)
|
||||||
unitFile.Add(UnitGroup, "After", volumeServiceName)
|
serviceUnitFile.Add(UnitGroup, "After", volumeServiceName)
|
||||||
}
|
}
|
||||||
|
|
||||||
return source
|
return source, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleHealth(unitFile *parser.UnitFile, groupName string, podman *PodmanCmdline) {
|
func handleHealth(unitFile *parser.UnitFile, groupName string, podman *PodmanCmdline) {
|
||||||
|
@ -18,3 +18,5 @@ Mount=type=tmpfs,tmpfs-size=512M,destination=/path/in/container
|
|||||||
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=devpts,destination=/dev/pts"
|
## assert-podman-args-key-val "--mount" "," "type=devpts,destination=/dev/pts"
|
||||||
Mount=type=devpts,destination=/dev/pts
|
Mount=type=devpts,destination=/dev/pts
|
||||||
|
## assert-podman-args-key-val-regex "--mount" "," "type=bind,source=.*/podman_test.*/quadlet/path/on/host,destination=/path/in/container"
|
||||||
|
Mount=type=bind,source=./path/on/host,destination=/path/in/container
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
## assert-podman-args -v /host/dir:/container/volume
|
## assert-podman-args -v /host/dir:/container/volume
|
||||||
## assert-podman-args -v /host/dir2:/container/volume2:Z
|
## assert-podman-args -v /host/dir2:/container/volume2:Z
|
||||||
|
## assert-podman-args-regex -v .*/podman_test.*/quadlet/host/dir3:/container/volume3
|
||||||
## assert-podman-args -v named:/container/named
|
## assert-podman-args -v named:/container/named
|
||||||
## assert-podman-args -v systemd-quadlet:/container/quadlet localhost/imagename
|
## assert-podman-args -v systemd-quadlet:/container/quadlet localhost/imagename
|
||||||
|
|
||||||
@ -7,6 +8,7 @@
|
|||||||
Image=localhost/imagename
|
Image=localhost/imagename
|
||||||
Volume=/host/dir:/container/volume
|
Volume=/host/dir:/container/volume
|
||||||
Volume=/host/dir2:/container/volume2:Z
|
Volume=/host/dir2:/container/volume2:Z
|
||||||
|
Volume=./host/dir3:/container/volume3
|
||||||
Volume=/container/empty
|
Volume=/container/empty
|
||||||
Volume=named:/container/named
|
Volume=named:/container/named
|
||||||
Volume=quadlet.volume:/container/quadlet
|
Volume=quadlet.volume:/container/quadlet
|
||||||
|
@ -187,7 +187,24 @@ func keyValueStringToMap(keyValueString, separator string) map[string]string {
|
|||||||
return keyValMap
|
return keyValMap
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *quadletTestcase) assertPodmanArgsKeyVal(args []string, unit *parser.UnitFile, key string) bool {
|
func keyValMapEqualRegex(expectedKeyValMap, actualKeyValMap map[string]string) bool {
|
||||||
|
if len(expectedKeyValMap) != len(actualKeyValMap) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for key, expectedValue := range expectedKeyValMap {
|
||||||
|
actualValue, ok := actualKeyValMap[key]
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
matched, err := regexp.MatchString(expectedValue, actualValue)
|
||||||
|
if err != nil || !matched {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *quadletTestcase) assertPodmanArgsKeyVal(args []string, unit *parser.UnitFile, key string, allowRegex bool) bool {
|
||||||
podmanArgs, _ := unit.LookupLastArgs("Service", key)
|
podmanArgs, _ := unit.LookupLastArgs("Service", key)
|
||||||
|
|
||||||
expectedKeyValMap := keyValueStringToMap(args[2], args[1])
|
expectedKeyValMap := keyValueStringToMap(args[2], args[1])
|
||||||
@ -200,7 +217,11 @@ func (t *quadletTestcase) assertPodmanArgsKeyVal(args []string, unit *parser.Uni
|
|||||||
|
|
||||||
argKeyLocation += subListLocation
|
argKeyLocation += subListLocation
|
||||||
actualKeyValMap := keyValueStringToMap(podmanArgs[argKeyLocation+1], args[1])
|
actualKeyValMap := keyValueStringToMap(podmanArgs[argKeyLocation+1], args[1])
|
||||||
if reflect.DeepEqual(expectedKeyValMap, actualKeyValMap) {
|
if allowRegex {
|
||||||
|
if keyValMapEqualRegex(expectedKeyValMap, actualKeyValMap) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} else if reflect.DeepEqual(expectedKeyValMap, actualKeyValMap) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,7 +260,11 @@ func (t *quadletTestcase) assertStartPodmanArgsRegex(args []string, unit *parser
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *quadletTestcase) assertStartPodmanArgsKeyVal(args []string, unit *parser.UnitFile) bool {
|
func (t *quadletTestcase) assertStartPodmanArgsKeyVal(args []string, unit *parser.UnitFile) bool {
|
||||||
return t.assertPodmanArgsKeyVal(args, unit, "ExecStart")
|
return t.assertPodmanArgsKeyVal(args, unit, "ExecStart", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *quadletTestcase) assertStartPodmanArgsKeyValRegex(args []string, unit *parser.UnitFile) bool {
|
||||||
|
return t.assertPodmanArgsKeyVal(args, unit, "ExecStart", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *quadletTestcase) assertStartPodmanFinalArgs(args []string, unit *parser.UnitFile) bool {
|
func (t *quadletTestcase) assertStartPodmanFinalArgs(args []string, unit *parser.UnitFile) bool {
|
||||||
@ -309,6 +334,8 @@ func (t *quadletTestcase) doAssert(check []string, unit *parser.UnitFile, sessio
|
|||||||
ok = t.assertStartPodmanArgsRegex(args, unit)
|
ok = t.assertStartPodmanArgsRegex(args, unit)
|
||||||
case "assert-podman-args-key-val":
|
case "assert-podman-args-key-val":
|
||||||
ok = t.assertStartPodmanArgsKeyVal(args, unit)
|
ok = t.assertStartPodmanArgsKeyVal(args, unit)
|
||||||
|
case "assert-podman-args-key-val-regex":
|
||||||
|
ok = t.assertStartPodmanArgsKeyValRegex(args, unit)
|
||||||
case "assert-podman-final-args":
|
case "assert-podman-final-args":
|
||||||
ok = t.assertStartPodmanFinalArgs(args, unit)
|
ok = t.assertStartPodmanFinalArgs(args, unit)
|
||||||
case "assert-podman-final-args-regex":
|
case "assert-podman-final-args-regex":
|
||||||
|
Reference in New Issue
Block a user