quadlet: add support for the UpheldBy option in the Install section

This adds support for the UpheldBy option in quadlet files. The UpheldBy option
is the counterpart to the Upholds option added in systemd v249 and is
similar to the existing WantedBy and RequiredBy options.

See https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html#Upholds=.

Signed-off-by: John Schug <john.ips.schug@gmail.com>
This commit is contained in:
John Schug
2025-03-26 16:49:23 -07:00
parent 71ed3f0fa9
commit a0cae65c13
3 changed files with 21 additions and 16 deletions

View File

@ -449,6 +449,18 @@ func generateServiceFile(service *parser.UnitFile) error {
return nil
}
func gatherDependentSymlinks(service *parser.UnitFile, key, dir, filename string) []string {
symlinks := make([]string, 0)
groupBy := service.LookupAllStrv(quadlet.InstallGroup, key)
for _, groupByUnit := range groupBy {
// Only allow filenames, not paths
if !strings.Contains(groupByUnit, "/") {
symlinks = append(symlinks, fmt.Sprintf("%s.%s/%s", groupByUnit, dir, filename))
}
}
return symlinks
}
// This parses the `Install` group of the unit file and creates the required
// symlinks to get systemd to start the newly generated file as needed.
// In a traditional setup this is done by "systemctl enable", but that doesn't
@ -476,21 +488,9 @@ func enableServiceFile(outputPath string, service *parser.UnitFile) {
}
if serviceFilename != "" {
wantedBy := service.LookupAllStrv(quadlet.InstallGroup, "WantedBy")
for _, wantedByUnit := range wantedBy {
// Only allow filenames, not paths
if !strings.Contains(wantedByUnit, "/") {
symlinks = append(symlinks, fmt.Sprintf("%s.wants/%s", wantedByUnit, serviceFilename))
}
}
requiredBy := service.LookupAllStrv(quadlet.InstallGroup, "RequiredBy")
for _, requiredByUnit := range requiredBy {
// Only allow filenames, not paths
if !strings.Contains(requiredByUnit, "/") {
symlinks = append(symlinks, fmt.Sprintf("%s.requires/%s", requiredByUnit, serviceFilename))
}
}
symlinks = append(symlinks, gatherDependentSymlinks(service, "WantedBy", "wants", serviceFilename)...)
symlinks = append(symlinks, gatherDependentSymlinks(service, "RequiredBy", "requires", serviceFilename)...)
symlinks = append(symlinks, gatherDependentSymlinks(service, "UpheldBy", "upholds", serviceFilename)...)
}
for _, symlinkRel := range symlinks {

View File

@ -129,7 +129,7 @@ For example, to start a container on boot, add something like this to the file:
WantedBy=default.target
```
Currently, only the `Alias`, `WantedBy` and `RequiredBy` keys are supported.
Currently, only the `Alias`, `WantedBy`, `RequiredBy`, and `UpheldBy` keys are supported.
The Install section can be part of the main file, or it can be in a
separate drop-in file as described above. The latter allows you to

View File

@ -7,6 +7,9 @@
## assert-symlink req1.service.requires/install.service ../install.service
## assert-symlink req2.service.requires/install.service ../install.service
## assert-symlink req3.service.requires/install.service ../install.service
## assert-symlink up1.service.upholds/install.service ../install.service
## assert-symlink up2.service.upholds/install.service ../install.service
## assert-symlink up3.service.upholds/install.service ../install.service
[Container]
Image=localhost/imagename
@ -19,3 +22,5 @@ WantedBy=want1.service want2.service
WantedBy=want3.service
RequiredBy=req1.service req2.service
RequiredBy=req3.service
UpheldBy=up1.service up2.service
UpheldBy=up3.service