From 8d190704a69fe3f98c21651d99f04915d8b0b769 Mon Sep 17 00:00:00 2001 From: Ygal Blum Date: Mon, 17 Jul 2023 15:54:29 +0300 Subject: [PATCH] Quadlet - Allow setting Service WorkingDirectory for Kube units Add key for Quadlet to set WorkingDirectory to the directory of the YAML or Unit file Add Doc Add E2E tests Add System test Signed-off-by: Ygal Blum --- docs/source/markdown/podman-systemd.unit.5.md | 31 ++++++---- pkg/systemd/quadlet/quadlet.go | 47 +++++++++++++++ test/e2e/quadlet/workingdir-service.kube | 8 +++ test/e2e/quadlet/workingdir-unit.kube | 5 ++ test/e2e/quadlet/workingdir-yaml-abs.kube | 5 ++ test/e2e/quadlet/workingdir-yaml-rel.kube | 5 ++ test/e2e/quadlet_test.go | 4 ++ test/system/252-quadlet.bats | 60 +++++++++++++++++++ 8 files changed, 155 insertions(+), 10 deletions(-) create mode 100644 test/e2e/quadlet/workingdir-service.kube create mode 100644 test/e2e/quadlet/workingdir-unit.kube create mode 100644 test/e2e/quadlet/workingdir-yaml-abs.kube create mode 100644 test/e2e/quadlet/workingdir-yaml-rel.kube 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 d4badd194a..883284def6 100644 --- a/test/system/252-quadlet.bats +++ b/test/system/252-quadlet.bats @@ -897,4 +897,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