diff --git a/docs/source/markdown/podman-systemd.unit.5.md b/docs/source/markdown/podman-systemd.unit.5.md index d8398eaa6f..ed89f6e53c 100644 --- a/docs/source/markdown/podman-systemd.unit.5.md +++ b/docs/source/markdown/podman-systemd.unit.5.md @@ -517,16 +517,17 @@ There is only one required key, `Yaml`, which defines the path to the Kubernetes Valid options for `[Kube]` are listed below: -| **[Kube] options** | **podman kube play equivalent** | -| ----------------------------------- | ------------------------------------------------ | -| AutoUpdate=registry | --annotation "io.containers.autoupdate=registry" | -| ConfigMap=/tmp/config.map | --config-map /tmp/config.map | -| LogDriver=journald | --log-driver journald | -| Network=host | --net host | -| PodmanArgs=\-\-annotation=key=value | --annotation=key=value | -| PublishPort=59-60 | --publish=59-60 | -| UserNS=keep-id:uid=200,gid=210 | --userns keep-id:uid=200,gid=210 | -| Yaml=/tmp/kube.yaml | podman kube play /tmp/kube.yaml | +| **[Kube] options** | **podman kube play equivalent** | +| ----------------------------------- | -----------------------------------------------------------------| +| AutoUpdate=registry | --annotation "io.containers.autoupdate=registry" | +| ConfigMap=/tmp/config.map | --config-map /tmp/config.map | +| LogDriver=journald | --log-driver journald | +| Network=host | --net host | +| PodmanArgs=\-\-annotation=key=value | --annotation=key=value | +| PublishPort=59-60 | --publish=59-60 | +| SetWorkingDirectory=yaml | Set `WorkingDirectory` of unit file to location of the YAML file | +| UserNS=keep-id:uid=200,gid=210 | --userns keep-id:uid=200,gid=210 | +| Yaml=/tmp/kube.yaml | podman kube play /tmp/kube.yaml | Supported keys in the `[Kube]` section are: @@ -609,6 +610,16 @@ entry from the unit file takes precedence This key can be listed multiple times. +### `SetWorkingDirectory=` + +Set the `WorkingDirectory` field of the `Service` group of the Systemd service unit file. +Used to allow `podman kube play` to correctly resolve relative paths. +Supported values are `yaml` and `unit` to set the working directory to that of the YAML or Quadlet Unit file respectively. + +Alternatively, users can explicitly set the `WorkingDirectory` field of the `Service` group in the `.kube` file. +Please note that if the `WorkingDirectory` field of the `Service` group is set, +Quadlet will not set it even if `SetWorkingDirectory` is set + ### `Unmask=` Specify the paths to unmask separated by a colon. unmask=ALL or /path/1:/path/2, or shell expanded paths (/proc/*): diff --git a/pkg/systemd/quadlet/quadlet.go b/pkg/systemd/quadlet/quadlet.go index a1190d4dfe..34b735824a 100644 --- a/pkg/systemd/quadlet/quadlet.go +++ b/pkg/systemd/quadlet/quadlet.go @@ -35,6 +35,11 @@ const ( XVolumeGroup = "X-Volume" ) +// Systemd Unit file keys +const ( + ServiceKeyWorkingDirectory = "WorkingDirectory" +) + // All the supported quadlet keys const ( KeyAddCapability = "AddCapability" @@ -103,6 +108,7 @@ const ( KeySecurityLabelNested = "SecurityLabelNested" KeySecurityLabelType = "SecurityLabelType" KeySecret = "Secret" + KeySetWorkingDirectory = "SetWorkingDirectory" KeySysctl = "Sysctl" KeyTimezone = "Timezone" KeyTmpfs = "Tmpfs" @@ -226,6 +232,7 @@ var ( KeyRemapUID: true, KeyRemapUIDSize: true, KeyRemapUsers: true, + KeySetWorkingDirectory: true, KeyUserNS: true, KeyYaml: true, } @@ -1019,6 +1026,11 @@ func ConvertKube(kube *parser.UnitFile, names map[string]string, isUser bool) (* execStop.add(yamlPath) service.AddCmdline(ServiceGroup, "ExecStopPost", execStop.Args) + err = handleSetWorkingDirectory(kube, service) + if err != nil { + return nil, err + } + return service, nil } @@ -1288,3 +1300,38 @@ func handlePodmanArgs(unitFile *parser.UnitFile, groupName string, podman *Podma podman.add(podmanArgs...) } } + +func handleSetWorkingDirectory(kube, serviceUnitFile *parser.UnitFile) error { + // If WorkingDirectory is already set in the Service section do not change it + workingDir, ok := kube.Lookup(ServiceGroup, ServiceKeyWorkingDirectory) + if ok && len(workingDir) > 0 { + return nil + } + + setWorkingDirectory, ok := kube.Lookup(KubeGroup, KeySetWorkingDirectory) + if !ok || len(setWorkingDirectory) == 0 { + return nil + } + + var relativeToFile string + switch strings.ToLower(setWorkingDirectory) { + case "yaml": + relativeToFile, ok = kube.Lookup(KubeGroup, KeyYaml) + if !ok { + return fmt.Errorf("no Yaml key specified") + } + case "unit": + relativeToFile = kube.Path + default: + return fmt.Errorf("unsupported value for %s: %s ", ServiceKeyWorkingDirectory, setWorkingDirectory) + } + + fileInWorkingDir, err := getAbsolutePath(kube, relativeToFile) + if err != nil { + return err + } + + serviceUnitFile.Add(ServiceGroup, ServiceKeyWorkingDirectory, filepath.Dir(fileInWorkingDir)) + + return nil +} diff --git a/test/e2e/quadlet/workingdir-service.kube b/test/e2e/quadlet/workingdir-service.kube new file mode 100644 index 0000000000..aa27987483 --- /dev/null +++ b/test/e2e/quadlet/workingdir-service.kube @@ -0,0 +1,8 @@ +## assert-key-is-regex "Service" "WorkingDirectory" "/etc/containers/systemd" + +[Service] +WorkingDirectory=/etc/containers/systemd + +[Kube] +Yaml=deployment.yml +SetWorkingDirectory=unit diff --git a/test/e2e/quadlet/workingdir-unit.kube b/test/e2e/quadlet/workingdir-unit.kube new file mode 100644 index 0000000000..ef6adef606 --- /dev/null +++ b/test/e2e/quadlet/workingdir-unit.kube @@ -0,0 +1,5 @@ +## assert-key-is-regex "Service" "WorkingDirectory" ".*/podman_test.*/quadlet" + +[Kube] +Yaml=deployment.yml +SetWorkingDirectory=unit diff --git a/test/e2e/quadlet/workingdir-yaml-abs.kube b/test/e2e/quadlet/workingdir-yaml-abs.kube new file mode 100644 index 0000000000..734fafdf30 --- /dev/null +++ b/test/e2e/quadlet/workingdir-yaml-abs.kube @@ -0,0 +1,5 @@ +## assert-key-is "Service" "WorkingDirectory" "/etc/containers/systemd" + +[Kube] +Yaml=/etc/containers/systemd/deployment.yml +SetWorkingDirectory=yaml diff --git a/test/e2e/quadlet/workingdir-yaml-rel.kube b/test/e2e/quadlet/workingdir-yaml-rel.kube new file mode 100644 index 0000000000..ddde1c361d --- /dev/null +++ b/test/e2e/quadlet/workingdir-yaml-rel.kube @@ -0,0 +1,5 @@ +## assert-key-is-regex "Service" "WorkingDirectory" ".*/podman_test.*/quadlet/myservice" + +[Kube] +Yaml=./myservice/deployment.yml +SetWorkingDirectory=yaml diff --git a/test/e2e/quadlet_test.go b/test/e2e/quadlet_test.go index 8150c1414d..1d2e499d78 100644 --- a/test/e2e/quadlet_test.go +++ b/test/e2e/quadlet_test.go @@ -624,6 +624,10 @@ BOGUS=foo Entry("Kube - User Remap Auto", "remap-auto.kube", 0, ""), Entry("Kube - User Remap Manual", "remap-manual.kube", 1, "converting \"remap-manual.kube\": RemapUsers=manual is not supported"), Entry("Syslog Identifier", "syslog.identifier.kube", 0, ""), + Entry("Kube - Working Directory YAML Absolute Path", "workingdir-yaml-abs.kube", 0, ""), + Entry("Kube - Working Directory YAML Relative Path", "workingdir-yaml-rel.kube", 0, ""), + Entry("Kube - Working Directory Unit", "workingdir-unit.kube", 0, ""), + Entry("Kube - Working Directory already in Service", "workingdir-service.kube", 0, ""), Entry("Network - Basic", "basic.network", 0, ""), Entry("Network - Disable DNS", "disable-dns.network", 0, ""), diff --git a/test/system/252-quadlet.bats b/test/system/252-quadlet.bats index b13fd8f8b1..7c1007a59a 100644 --- a/test/system/252-quadlet.bats +++ b/test/system/252-quadlet.bats @@ -923,4 +923,64 @@ EOF run_podman rmi $(pause_image) } +@test "quadlet kube - Working Directory" { + yaml_source="$PODMAN_TMPDIR/basic_$(random_string).yaml" + local_path=local_path$(random_string) + pod_name=test_pod + container_name=test + + cat >$yaml_source < $quadlet_file < /test/test.txt" + is $(cat $PODMAN_TMPDIR/$local_path/test.txt) "hello" + + service_cleanup $QUADLET_SERVICE_NAME inactive + run_podman rmi $(pause_image) +} + # vim: filetype=sh