diff --git a/pkg/systemd/quadlet/quadlet.go b/pkg/systemd/quadlet/quadlet.go index 5fdbdda5ca..f4ad3496f7 100644 --- a/pkg/systemd/quadlet/quadlet.go +++ b/pkg/systemd/quadlet/quadlet.go @@ -559,15 +559,7 @@ func ConvertContainer(container *parser.UnitFile, isUser bool, unitsInfoMap map[ } } - containerName, ok := container.Lookup(ContainerGroup, KeyContainerName) - if !ok || len(containerName) == 0 { - // By default, We want to name the container by the service name - if strings.Contains(container.Filename, "@") { - containerName = "systemd-%p_%i" - } else { - containerName = "systemd-%N" - } - } + containerName := getContainerName(container) // Set PODMAN_SYSTEMD_UNIT so that podman auto-update can restart the service. service.Add(ServiceGroup, "Environment", "PODMAN_SYSTEMD_UNIT=%n") @@ -868,14 +860,46 @@ func ConvertContainer(container *parser.UnitFile, isUser bool, unitsInfoMap map[ service.AddCmdline(ServiceGroup, "ExecStart", podman.Args) + unitInfo.ResourceName = getContainerResourceName(container, unitInfo) + + return service, nil +} + +// Get the unresolved container name that may contain '%'. +func getContainerName(container *parser.UnitFile) string { + containerName, ok := container.Lookup(ContainerGroup, KeyContainerName) + if !ok || len(containerName) == 0 { + // By default, We want to name the container by the service name. + if strings.Contains(container.Filename, "@") { + containerName = "systemd-%p_%i" + } else { + containerName = "systemd-%N" + } + } + return containerName +} + +// Get the resolved container name that contains no '%'. +// Returns an empty string if not resolvable. +func getContainerResourceName(container *parser.UnitFile, unitInfo *UnitInfo) string { + if len(unitInfo.ResourceName) != 0 { + // Shortcut: already resolved before. + return unitInfo.ResourceName + } + + containerName := getContainerName(container) + // XXX: only %N is handled. // it is difficult to properly implement specifiers handling without consulting systemd. resourceName := strings.ReplaceAll(containerName, "%N", unitInfo.ServiceName) + if !strings.Contains(resourceName, "%") { unitInfo.ResourceName = resourceName + } else { + unitInfo.ResourceName = "" } - return service, nil + return unitInfo.ResourceName } func defaultOneshotServiceGroup(service *parser.UnitFile, remainAfterExit bool) { @@ -1793,8 +1817,15 @@ func addNetworks(quadletUnitFile *parser.UnitFile, groupName string, serviceUnit return fmt.Errorf("requested Quadlet unit %s was not found", quadletNetworkName) } + var resourceName string + if isContainerUnit { + resourceName = getContainerResourceName(quadletUnitFile, unitInfo) + } else { + resourceName = unitInfo.ResourceName + } + // XXX: this is usually because a '@' in service name - if len(unitInfo.ResourceName) == 0 { + if len(resourceName) == 0 { return fmt.Errorf("cannot get the resource name of %s", quadletNetworkName) } @@ -1808,12 +1839,12 @@ func addNetworks(quadletUnitFile *parser.UnitFile, groupName string, serviceUnit if isContainerUnit { return fmt.Errorf("extra options are not supported when joining another container's network") } - network = fmt.Sprintf("%s:%s", unitInfo.ResourceName, options) + network = fmt.Sprintf("%s:%s", resourceName, options) } else { if isContainerUnit { - network = fmt.Sprintf("container:%s", unitInfo.ResourceName) + network = fmt.Sprintf("container:%s", resourceName) } else { - network = unitInfo.ResourceName + network = resourceName } } }