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 <ygal.blum@gmail.com>
This commit is contained in:
Ygal Blum 2023-07-17 15:54:29 +03:00
parent 34a2a48e9c
commit 8d190704a6
8 changed files with 155 additions and 10 deletions

View File

@ -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/*):

View File

@ -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
}

View File

@ -0,0 +1,8 @@
## assert-key-is-regex "Service" "WorkingDirectory" "/etc/containers/systemd"
[Service]
WorkingDirectory=/etc/containers/systemd
[Kube]
Yaml=deployment.yml
SetWorkingDirectory=unit

View File

@ -0,0 +1,5 @@
## assert-key-is-regex "Service" "WorkingDirectory" ".*/podman_test.*/quadlet"
[Kube]
Yaml=deployment.yml
SetWorkingDirectory=unit

View File

@ -0,0 +1,5 @@
## assert-key-is "Service" "WorkingDirectory" "/etc/containers/systemd"
[Kube]
Yaml=/etc/containers/systemd/deployment.yml
SetWorkingDirectory=yaml

View File

@ -0,0 +1,5 @@
## assert-key-is-regex "Service" "WorkingDirectory" ".*/podman_test.*/quadlet/myservice"
[Kube]
Yaml=./myservice/deployment.yml
SetWorkingDirectory=yaml

View File

@ -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, ""),

View File

@ -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 <<EOF
apiVersion: v1
kind: Pod
metadata:
labels:
app: test
name: $pod_name
spec:
containers:
- command:
- "sh"
args:
- "-c"
- "echo STARTED CONTAINER; top -b"
image: $IMAGE
name: $container_name
volumeMounts:
- mountPath: /test
name: test-volume
volumes:
- name: test-volume
hostPath:
# directory location on host
path: ./$local_path
# this field is optional
type: DirectoryOrCreate
EOF
# Create the Quadlet file
local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).kube
cat > $quadlet_file <<EOF
[Kube]
Yaml=${yaml_source}
SetWorkingDirectory=yaml
EOF
run_quadlet "$quadlet_file"
service_setup $QUADLET_SERVICE_NAME
# Ensure we have output.
wait_for_output "STARTED CONTAINER" $pod_name-$container_name
run_podman container inspect --format "{{.State.Status}}" $pod_name-$container_name
is "$output" "running" "container should be started by systemd and hence be running"
run_podman ps
run_podman exec $pod_name-$container_name /bin/sh -c "echo hello > /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