Skip to content

Commit c2b5be1

Browse files
Merge pull request #25842 from ygalblum/quadlet-exec-reload
Quadlet - Add support for adding ExecReload command
2 parents 0c311be + fe107ff commit c2b5be1

File tree

6 files changed

+113
-0
lines changed

6 files changed

+113
-0
lines changed

docs/source/markdown/podman-systemd.unit.5.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,8 @@ Valid options for `[Container]` are listed below:
333333
| Pull=never | --pull never |
334334
| ReadOnly=true | --read-only |
335335
| ReadOnlyTmpfs=true | --read-only-tmpfs |
336+
| ReloadCmd=/usr/bin/command | Add ExecReload and run exec with the value |
337+
| ReloadSignal=SIGHUP | Add ExecReload and run kill with the signal |
336338
| Retry=5 | --retry=5 |
337339
| RetryDelay=5s | --retry-delay=5s |
338340
| Rootfs=/var/lib/rootfs | --rootfs /var/lib/rootfs |
@@ -784,6 +786,22 @@ If enabled, makes the image read-only.
784786

785787
If ReadOnly is set to `true`, mount a read-write tmpfs on /dev, /dev/shm, /run, /tmp, and /var/tmp.
786788

789+
### `ReloadCmd=`
790+
791+
Add `ExecReload` line to the `Service` that runs ` podman exec` with this command in this container.
792+
793+
In order to execute the reload run `systemctl reload <Service>`
794+
795+
Mutually exclusive with `ReloadSignal`
796+
797+
### `ReloadSignal=`
798+
799+
Add `ExecReload` line to the `Service` that runs `podman kill` with this signal which sends the signal to the main container process.
800+
801+
In order to execute the reload run `systemctl reload <Service>`
802+
803+
Mutually exclusive with `ReloadCmd`
804+
787805
### `Retry=`
788806

789807
Number of times to retry the image pull when a HTTP error occurs. Equivalent to the Podman `--retry` option.

pkg/systemd/quadlet/quadlet.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ const (
139139
KeyPull = "Pull"
140140
KeyReadOnly = "ReadOnly"
141141
KeyReadOnlyTmpfs = "ReadOnlyTmpfs"
142+
KeyReloadCmd = "ReloadCmd"
143+
KeyReloadSignal = "ReloadSignal"
142144
KeyRemapGid = "RemapGid" // deprecated
143145
KeyRemapUid = "RemapUid" // deprecated
144146
KeyRemapUidSize = "RemapUidSize" // deprecated
@@ -256,6 +258,8 @@ var (
256258
KeyPull: true,
257259
KeyReadOnly: true,
258260
KeyReadOnlyTmpfs: true,
261+
KeyReloadCmd: true,
262+
KeyReloadSignal: true,
259263
KeyRemapGid: true,
260264
KeyRemapUid: true,
261265
KeyRemapUidSize: true,
@@ -578,6 +582,10 @@ func ConvertContainer(container *parser.UnitFile, isUser bool, unitsInfoMap map[
578582
serviceStopCmd.Args[0] = fmt.Sprintf("-%s", serviceStopCmd.Args[0])
579583
service.AddCmdline(ServiceGroup, "ExecStopPost", serviceStopCmd.Args)
580584

585+
if err := handleExecReload(container, service, ContainerGroup); err != nil {
586+
return nil, warnings, err
587+
}
588+
581589
podman := createBasePodmanCommand(container, ContainerGroup)
582590

583591
podman.add("run")
@@ -2226,3 +2234,29 @@ func addDefaultDependencies(service *parser.UnitFile, isUser bool) {
22262234
service.PrependUnitLine(UnitGroup, "Wants", networkUnit)
22272235
}
22282236
}
2237+
2238+
func handleExecReload(quadletUnitFile, serviceUnitFile *parser.UnitFile, groupName string) error {
2239+
reloadSignal, signalOk := quadletUnitFile.Lookup(groupName, KeyReloadSignal)
2240+
signalOk = signalOk && len(reloadSignal) > 0
2241+
reloadcmd, cmdOk := quadletUnitFile.LookupLastArgs(groupName, KeyReloadCmd)
2242+
cmdOk = cmdOk && len(reloadcmd) > 0
2243+
2244+
if !cmdOk && !signalOk {
2245+
return nil
2246+
}
2247+
2248+
if cmdOk && signalOk {
2249+
return fmt.Errorf("%s and %s are mutually exclusive but both are set", KeyReloadCmd, KeyReloadSignal)
2250+
}
2251+
2252+
serviceReloadCmd := createBasePodmanCommand(quadletUnitFile, groupName)
2253+
if cmdOk {
2254+
serviceReloadCmd.add("exec", "--cidfile=%t/%N.cid")
2255+
serviceReloadCmd.add(reloadcmd...)
2256+
} else {
2257+
serviceReloadCmd.add("kill", "--cidfile=%t/%N.cid", "--signal", reloadSignal)
2258+
}
2259+
serviceUnitFile.AddCmdline(ServiceGroup, "ExecReload", serviceReloadCmd.Args)
2260+
2261+
return nil
2262+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
## assert-failed
2+
## assert-stderr-contains "ReloadCmd and ReloadSignal are mutually exclusive but both are set"
3+
4+
[Container]
5+
Image=localhost/imagename
6+
ReloadCmd=/usr/bin/command
7+
ReloadSignal=SIGHUP
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
## assert-podman-reload-args "exec"
2+
## assert-podman-reload-args "--cidfile=%t/%N.cid"
3+
## assert-podman-reload-final-args "/some/binary file" "--arg1" "arg 2"
4+
5+
[Container]
6+
Image=localhost/imagename
7+
ReloadCmd="/some/binary file" --arg1 \
8+
"arg 2"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
## assert-podman-reload-args "kill"
2+
## assert-podman-reload-args "--cidfile=%t/%N.cid"
3+
## assert-podman-reload-args "--signal" "SIGHUP"
4+
5+
[Container]
6+
Image=localhost/imagename
7+
ReloadSignal=SIGHUP

test/e2e/quadlet_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,30 @@ func (t *quadletTestcase) assertStopPostPodmanArgsKeyValRegex(args []string, uni
477477
return t.assertPodmanArgsKeyVal(args, unit, "ExecStopPost", true, false)
478478
}
479479

480+
func (t *quadletTestcase) assertReloadPodmanArgs(args []string, unit *parser.UnitFile) bool {
481+
return t.assertPodmanArgs(args, unit, "ExecReload", false, false)
482+
}
483+
484+
func (t *quadletTestcase) assertReloadPodmanGlobalArgs(args []string, unit *parser.UnitFile) bool {
485+
return t.assertPodmanArgs(args, unit, "ExecReload", false, true)
486+
}
487+
488+
func (t *quadletTestcase) assertReloadPodmanFinalArgs(args []string, unit *parser.UnitFile) bool {
489+
return t.assertPodmanFinalArgs(args, unit, "ExecReload")
490+
}
491+
492+
func (t *quadletTestcase) assertReloadPodmanFinalArgsRegex(args []string, unit *parser.UnitFile) bool {
493+
return t.assertPodmanFinalArgsRegex(args, unit, "ExecReload")
494+
}
495+
496+
func (t *quadletTestcase) assertReloadPodmanArgsKeyVal(args []string, unit *parser.UnitFile) bool {
497+
return t.assertPodmanArgsKeyVal(args, unit, "ExecReload", false, false)
498+
}
499+
500+
func (t *quadletTestcase) assertReloadPodmanArgsKeyValRegex(args []string, unit *parser.UnitFile) bool {
501+
return t.assertPodmanArgsKeyVal(args, unit, "ExecReload", true, false)
502+
}
503+
480504
func (t *quadletTestcase) assertSymlink(args []string, unit *parser.UnitFile) bool {
481505
Expect(args).To(HaveLen(2))
482506
symlink := args[0]
@@ -590,6 +614,18 @@ func (t *quadletTestcase) doAssert(check []string, unit *parser.UnitFile, sessio
590614
ok = t.assertStopPostPodmanArgsKeyVal(args, unit)
591615
case "assert-podman-stop-post-args-key-val-regex":
592616
ok = t.assertStopPostPodmanArgsKeyValRegex(args, unit)
617+
case "assert-podman-reload-args":
618+
ok = t.assertReloadPodmanArgs(args, unit)
619+
case "assert-podman-reload-global-args":
620+
ok = t.assertReloadPodmanGlobalArgs(args, unit)
621+
case "assert-podman-reload-final-args":
622+
ok = t.assertReloadPodmanFinalArgs(args, unit)
623+
case "assert-podman-reload-final-args-regex":
624+
ok = t.assertReloadPodmanFinalArgsRegex(args, unit)
625+
case "assert-podman-reload-args-key-val":
626+
ok = t.assertReloadPodmanArgsKeyVal(args, unit)
627+
case "assert-podman-reload-args-key-val-regex":
628+
ok = t.assertReloadPodmanArgsKeyValRegex(args, unit)
593629

594630
default:
595631
return fmt.Errorf("Unsupported assertion %s", op)
@@ -926,6 +962,8 @@ BOGUS=foo
926962
Entry("CgroupMode", "cgroups-mode.container"),
927963
Entry("Container - No Default Dependencies", "no_deps.container"),
928964
Entry("retry.container", "retry.container"),
965+
Entry("reloadcmd.container", "reloadcmd.container"),
966+
Entry("reloadsignal.container", "reloadsignal.container"),
929967

930968
Entry("basic.volume", "basic.volume"),
931969
Entry("device-copy.volume", "device-copy.volume"),
@@ -1063,6 +1101,7 @@ BOGUS=foo
10631101
Entry("pod.not-found.container", "pod.not-found.container", "converting \"pod.not-found.container\": quadlet pod unit not-found.pod does not exist"),
10641102
Entry("subidmapping-with-remap.container", "subidmapping-with-remap.container", "converting \"subidmapping-with-remap.container\": deprecated Remap keys are set along with explicit mapping keys"),
10651103
Entry("userns-with-remap.container", "userns-with-remap.container", "converting \"userns-with-remap.container\": deprecated Remap keys are set along with explicit mapping keys"),
1104+
Entry("reloadboth.container", "reloadboth.container", "converting \"reloadboth.container\": ReloadCmd and ReloadSignal are mutually exclusive but both are set"),
10661105

10671106
Entry("image-no-image.volume", "image-no-image.volume", "converting \"image-no-image.volume\": the key Image is mandatory when using the image driver"),
10681107
Entry("Volume - Quadlet image (.build) not found", "build-not-found.quadlet.volume", "converting \"build-not-found.quadlet.volume\": requested Quadlet image not-found.build was not found"),

0 commit comments

Comments
 (0)