diff --git a/cmd/quadlet/main.go b/cmd/quadlet/main.go index 4ad7c8f8b2..eef05d30ae 100644 --- a/cmd/quadlet/main.go +++ b/cmd/quadlet/main.go @@ -496,34 +496,47 @@ func warnIfAmbiguousName(unit *parser.UnitFile, group string) { } } -func generatePodsInfoMap(units []*parser.UnitFile) map[string]*quadlet.PodInfo { - podsInfoMap := make(map[string]*quadlet.PodInfo) +func generateUnitsInfoMap(units []*parser.UnitFile) map[string]*quadlet.UnitInfo { + unitsInfoMap := make(map[string]*quadlet.UnitInfo) for _, unit := range units { - if !strings.HasSuffix(unit.Filename, ".pod") { - continue - } - - serviceName := quadlet.GetPodServiceName(unit) - podsInfoMap[unit.Filename] = &quadlet.PodInfo{ - ServiceName: serviceName, - Containers: make([]string, 0), - } - } + var serviceName string + var containers []string + var resourceName string - return podsInfoMap -} - -func prefillBuiltImageNames(units []*parser.UnitFile, resourceNames map[string]string) { - for _, unit := range units { - if !strings.HasSuffix(unit.Filename, ".build") { + switch { + case strings.HasSuffix(unit.Filename, ".container"): + serviceName = quadlet.GetContainerServiceName(unit) + case strings.HasSuffix(unit.Filename, ".volume"): + serviceName = quadlet.GetVolumeServiceName(unit) + case strings.HasSuffix(unit.Filename, ".kube"): + serviceName = quadlet.GetKubeServiceName(unit) + case strings.HasSuffix(unit.Filename, ".network"): + serviceName = quadlet.GetNetworkServiceName(unit) + case strings.HasSuffix(unit.Filename, ".image"): + serviceName = quadlet.GetImageServiceName(unit) + case strings.HasSuffix(unit.Filename, ".build"): + serviceName = quadlet.GetBuildServiceName(unit) + // Prefill resouceNames for .build files. This is significantly less complex than + // pre-computing all resourceNames for all Quadlet types (which is rather complex for a few + // types), but still breaks the dependency cycle between .volume and .build ([Volume] can + // have Image=some.build, and [Build] can have Volume=some.volume:/some-volume) + resourceName = quadlet.GetBuiltImageName(unit) + case strings.HasSuffix(unit.Filename, ".pod"): + serviceName = quadlet.GetPodServiceName(unit) + containers = make([]string, 0) + default: + Logf("Unsupported file type %q", unit.Filename) continue } - imageName := quadlet.GetBuiltImageName(unit) - if len(imageName) > 0 { - resourceNames[unit.Filename] = imageName + unitsInfoMap[unit.Filename] = &quadlet.UnitInfo{ + ServiceName: serviceName, + Containers: containers, + ResourceName: resourceName, } } + + return unitsInfoMap } func main() { @@ -622,40 +635,30 @@ func process() error { }) // Generate the PodsInfoMap to allow containers to link to their pods and add themselves to the pod's containers list - podsInfoMap := generatePodsInfoMap(units) - - // A map of network/volume unit file-names, against their calculated names, as needed by Podman. - var resourceNames = make(map[string]string) - - // Prefill resouceNames for .build files. This is significantly less complex than - // pre-computing all resourceNames for all Quadlet types (which is rather complex for a few - // types), but still breaks the dependency cycle between .volume and .build ([Volume] can - // have Image=some.build, and [Build] can have Volume=some.volume:/some-volume) - prefillBuiltImageNames(units, resourceNames) + unitsInfoMap := generateUnitsInfoMap(units) for _, unit := range units { var service *parser.UnitFile - var name string var err error switch { case strings.HasSuffix(unit.Filename, ".container"): warnIfAmbiguousName(unit, quadlet.ContainerGroup) - service, err = quadlet.ConvertContainer(unit, resourceNames, isUserFlag, podsInfoMap) + service, err = quadlet.ConvertContainer(unit, isUserFlag, unitsInfoMap) case strings.HasSuffix(unit.Filename, ".volume"): warnIfAmbiguousName(unit, quadlet.VolumeGroup) - service, name, err = quadlet.ConvertVolume(unit, unit.Filename, resourceNames) + service, err = quadlet.ConvertVolume(unit, unit.Filename, unitsInfoMap) case strings.HasSuffix(unit.Filename, ".kube"): - service, err = quadlet.ConvertKube(unit, resourceNames, isUserFlag) + service, err = quadlet.ConvertKube(unit, unitsInfoMap, isUserFlag) case strings.HasSuffix(unit.Filename, ".network"): - service, name, err = quadlet.ConvertNetwork(unit, unit.Filename) + service, err = quadlet.ConvertNetwork(unit, unit.Filename, unitsInfoMap) case strings.HasSuffix(unit.Filename, ".image"): warnIfAmbiguousName(unit, quadlet.ImageGroup) - service, name, err = quadlet.ConvertImage(unit) + service, err = quadlet.ConvertImage(unit, unitsInfoMap) case strings.HasSuffix(unit.Filename, ".build"): - service, name, err = quadlet.ConvertBuild(unit, resourceNames) + service, err = quadlet.ConvertBuild(unit, unitsInfoMap) case strings.HasSuffix(unit.Filename, ".pod"): - service, err = quadlet.ConvertPod(unit, unit.Filename, podsInfoMap, resourceNames) + service, err = quadlet.ConvertPod(unit, unit.Filename, unitsInfoMap) default: Logf("Unsupported file type %q", unit.Filename) continue @@ -666,9 +669,6 @@ func process() error { continue } - if name != "" { - resourceNames[unit.Filename] = name - } service.Path = path.Join(outputPath, service.Filename) if dryRunFlag { diff --git a/pkg/systemd/quadlet/quadlet.go b/pkg/systemd/quadlet/quadlet.go index 4beaf081be..2762f7d06a 100644 --- a/pkg/systemd/quadlet/quadlet.go +++ b/pkg/systemd/quadlet/quadlet.go @@ -170,9 +170,15 @@ const ( KeyYaml = "Yaml" ) -type PodInfo struct { +type UnitInfo struct { + // The name of the generated systemd service unit ServiceName string - Containers []string + // The name of the podman resource created by the service + ResourceName string + + // For .pod units + // List of containers in a pod + Containers []string } var ( @@ -245,6 +251,7 @@ var ( KeySecurityLabelLevel: true, KeySecurityLabelNested: true, KeySecurityLabelType: true, + KeyServiceName: true, KeyShmSize: true, KeyStopSignal: true, KeyStopTimeout: true, @@ -275,6 +282,7 @@ var ( KeyLabel: true, KeyOptions: true, KeyPodmanArgs: true, + KeyServiceName: true, KeyType: true, KeyUser: true, KeyVolumeName: true, @@ -295,6 +303,7 @@ var ( KeyInternal: true, KeyNetworkName: true, KeyOptions: true, + KeyServiceName: true, KeySubnet: true, KeyPodmanArgs: true, } @@ -316,6 +325,7 @@ var ( KeyRemapUid: true, KeyRemapUidSize: true, KeyRemapUsers: true, + KeyServiceName: true, KeySetWorkingDirectory: true, KeyUserNS: true, KeyYaml: true, @@ -335,6 +345,7 @@ var ( KeyImageTag: true, KeyOS: true, KeyPodmanArgs: true, + KeyServiceName: true, KeyTLSVerify: true, KeyVariant: true, } @@ -359,6 +370,7 @@ var ( KeyPodmanArgs: true, KeyPull: true, KeySecret: true, + KeyServiceName: true, KeySetWorkingDirectory: true, KeyTarget: true, KeyTLSVerify: true, @@ -379,7 +391,11 @@ var ( } ) -func replaceExtension(name string, extension string, extraPrefix string, extraSuffix string) string { +func (u *UnitInfo) ServiceFileName() string { + return fmt.Sprintf("%s.service", u.ServiceName) +} + +func removeExtension(name string, extraPrefix string, extraSuffix string) string { baseName := name dot := strings.LastIndexByte(name, '.') @@ -387,7 +403,7 @@ func replaceExtension(name string, extension string, extraPrefix string, extraSu baseName = name[:dot] } - return extraPrefix + baseName + extraSuffix + extension + return extraPrefix + baseName + extraSuffix } func isURL(urlCandidate string) bool { @@ -456,9 +472,14 @@ func usernsOpts(kind string, opts []string) string { // service file (unit file with Service group) based on the options in the // Container group. // The original Container group is kept around as X-Container. -func ConvertContainer(container *parser.UnitFile, names map[string]string, isUser bool, podsInfoMap map[string]*PodInfo) (*parser.UnitFile, error) { +func ConvertContainer(container *parser.UnitFile, isUser bool, unitsInfoMap map[string]*UnitInfo) (*parser.UnitFile, error) { + unitInfo, ok := unitsInfoMap[container.Filename] + if !ok { + return nil, fmt.Errorf("internal error while processing container %s", container.Filename) + } + service := container.Dup() - service.Filename = replaceExtension(container.Filename, ".service", "", "") + service.Filename = unitInfo.ServiceFileName() // Add a dependency on network-online.target so the image pull does not happen // before network is ready @@ -491,7 +512,7 @@ func ConvertContainer(container *parser.UnitFile, names map[string]string, isUse if len(image) > 0 { var err error - if image, err = handleImageSource(image, service, names); err != nil { + if image, err = handleImageSource(image, service, unitsInfoMap); err != nil { return nil, err } } @@ -567,7 +588,9 @@ func ConvertContainer(container *parser.UnitFile, names map[string]string, isUse podman.addf("--tz=%s", timezone) } - addNetworks(container, ContainerGroup, service, names, podman) + if err := addNetworks(container, ContainerGroup, service, unitsInfoMap, podman); err != nil { + return nil, err + } networkAliases := container.LookupAll(ContainerGroup, KeyNetworkAlias) for _, networkAlias := range networkAliases { @@ -753,7 +776,7 @@ func ConvertContainer(container *parser.UnitFile, names map[string]string, isUse podman.add("--tmpfs", tmpfs) } - if err := addVolumes(container, service, ContainerGroup, names, podman); err != nil { + if err := addVolumes(container, service, ContainerGroup, unitsInfoMap, podman); err != nil { return nil, err } @@ -827,7 +850,7 @@ func ConvertContainer(container *parser.UnitFile, names map[string]string, isUse mounts := container.LookupAllArgs(ContainerGroup, KeyMount) for _, mount := range mounts { - mountStr, err := resolveContainerMountParams(container, service, mount, names) + mountStr, err := resolveContainerMountParams(container, service, mount, unitsInfoMap) if err != nil { return nil, err } @@ -845,7 +868,7 @@ func ConvertContainer(container *parser.UnitFile, names map[string]string, isUse podman.add("--pull", pull) } - if err := handlePod(container, service, ContainerGroup, podsInfoMap, podman); err != nil { + if err := handlePod(container, service, ContainerGroup, unitsInfoMap, podman); err != nil { return nil, err } @@ -881,12 +904,17 @@ func ConvertContainer(container *parser.UnitFile, names map[string]string, isUse // The original Network group is kept around as X-Network. // Also returns the canonical network name, either auto-generated or user-defined via the // NetworkName key-value. -func ConvertNetwork(network *parser.UnitFile, name string) (*parser.UnitFile, string, error) { +func ConvertNetwork(network *parser.UnitFile, name string, unitsInfoMap map[string]*UnitInfo) (*parser.UnitFile, error) { + unitInfo, ok := unitsInfoMap[network.Filename] + if !ok { + return nil, fmt.Errorf("internal error while processing network %s", network.Filename) + } + service := network.Dup() - service.Filename = replaceExtension(network.Filename, ".service", "", "-network") + service.Filename = unitInfo.ServiceFileName() if err := checkForUnknownKeys(network, NetworkGroup, supportedNetworkKeys); err != nil { - return nil, "", err + return nil, err } /* Rename old Network group to x-Network so that systemd ignores it */ @@ -895,7 +923,7 @@ func ConvertNetwork(network *parser.UnitFile, name string) (*parser.UnitFile, st // Derive network name from unit name (with added prefix), or use user-provided name. networkName, ok := network.Lookup(NetworkGroup, KeyNetworkName) if !ok || len(networkName) == 0 { - networkName = replaceExtension(name, "", "systemd-", "") + networkName = removeExtension(name, "systemd-", "") } // Need the containers filesystem mounted to start podman @@ -924,10 +952,10 @@ func ConvertNetwork(network *parser.UnitFile, name string) (*parser.UnitFile, st ipRanges := network.LookupAll(NetworkGroup, KeyIPRange) if len(subnets) > 0 { if len(gateways) > len(subnets) { - return nil, "", fmt.Errorf("cannot set more gateways than subnets") + return nil, fmt.Errorf("cannot set more gateways than subnets") } if len(ipRanges) > len(subnets) { - return nil, "", fmt.Errorf("cannot set more ranges than subnets") + return nil, fmt.Errorf("cannot set more ranges than subnets") } for i := range subnets { podman.addf("--subnet=%s", subnets[i]) @@ -939,7 +967,7 @@ func ConvertNetwork(network *parser.UnitFile, name string) (*parser.UnitFile, st } } } else if len(ipRanges) > 0 || len(gateways) > 0 { - return nil, "", fmt.Errorf("cannot set gateway or range without subnet") + return nil, fmt.Errorf("cannot set gateway or range without subnet") } if internal := network.LookupBooleanWithDefault(NetworkGroup, KeyInternal, false); internal { @@ -976,7 +1004,9 @@ func ConvertNetwork(network *parser.UnitFile, name string) (*parser.UnitFile, st // The default syslog identifier is the exec basename (podman) which isn't very useful here "SyslogIdentifier", "%N") - return service, networkName, nil + // Store the name of the created resource + unitInfo.ResourceName = networkName + return service, nil } // Convert a quadlet volume file (unit file with a Volume group) to a systemd @@ -985,12 +1015,17 @@ func ConvertNetwork(network *parser.UnitFile, name string) (*parser.UnitFile, st // The original Volume group is kept around as X-Volume. // Also returns the canonical volume name, either auto-generated or user-defined via the VolumeName // key-value. -func ConvertVolume(volume *parser.UnitFile, name string, names map[string]string) (*parser.UnitFile, string, error) { +func ConvertVolume(volume *parser.UnitFile, name string, unitsInfoMap map[string]*UnitInfo) (*parser.UnitFile, error) { + unitInfo, ok := unitsInfoMap[volume.Filename] + if !ok { + return nil, fmt.Errorf("internal error while processing network %s", volume.Filename) + } + service := volume.Dup() - service.Filename = replaceExtension(volume.Filename, ".service", "", "-volume") + service.Filename = unitInfo.ServiceFileName() if err := checkForUnknownKeys(volume, VolumeGroup, supportedVolumeKeys); err != nil { - return nil, "", err + return nil, err } /* Rename old Volume group to x-Volume so that systemd ignores it */ @@ -999,7 +1034,7 @@ func ConvertVolume(volume *parser.UnitFile, name string, names map[string]string // Derive volume name from unit name (with added prefix), or use user-provided name. volumeName, ok := volume.Lookup(VolumeGroup, KeyVolumeName) if !ok || len(volumeName) == 0 { - volumeName = replaceExtension(name, "", "systemd-", "") + volumeName = removeExtension(name, "systemd-", "") } // Need the containers filesystem mounted to start podman @@ -1023,11 +1058,11 @@ func ConvertVolume(volume *parser.UnitFile, name string, names map[string]string imageName, ok := volume.Lookup(VolumeGroup, KeyImage) if !ok { - return nil, "", fmt.Errorf("the key %s is mandatory when using the image driver", KeyImage) + return nil, fmt.Errorf("the key %s is mandatory when using the image driver", KeyImage) } - imageName, err := handleImageSource(imageName, service, names) + imageName, err := handleImageSource(imageName, service, unitsInfoMap) if err != nil { - return nil, "", err + return nil, err } opts.WriteString(imageName) @@ -1072,7 +1107,7 @@ func ConvertVolume(volume *parser.UnitFile, name string, names map[string]string if devValid { podman.add("--opt", fmt.Sprintf("type=%s", devType)) } else { - return nil, "", fmt.Errorf("key Type can't be used without Device") + return nil, fmt.Errorf("key Type can't be used without Device") } } @@ -1084,7 +1119,7 @@ func ConvertVolume(volume *parser.UnitFile, name string, names map[string]string } opts.WriteString(mountOpts) } else { - return nil, "", fmt.Errorf("key Options can't be used without Device") + return nil, fmt.Errorf("key Options can't be used without Device") } } } @@ -1108,12 +1143,20 @@ func ConvertVolume(volume *parser.UnitFile, name string, names map[string]string // The default syslog identifier is the exec basename (podman) which isn't very useful here "SyslogIdentifier", "%N") - return service, volumeName, nil + // Store the name of the created resource + unitInfo.ResourceName = volumeName + + return service, nil } -func ConvertKube(kube *parser.UnitFile, names map[string]string, isUser bool) (*parser.UnitFile, error) { +func ConvertKube(kube *parser.UnitFile, unitsInfoMap map[string]*UnitInfo, isUser bool) (*parser.UnitFile, error) { + unitInfo, ok := unitsInfoMap[kube.Filename] + if !ok { + return nil, fmt.Errorf("internal error while processing network %s", kube.Filename) + } + service := kube.Dup() - service.Filename = replaceExtension(kube.Filename, ".service", "", "") + service.Filename = unitInfo.ServiceFileName() if kube.Path != "" { service.Add(UnitGroup, "SourcePath", kube.Path) @@ -1192,7 +1235,9 @@ func ConvertKube(kube *parser.UnitFile, names map[string]string, isUser bool) (* return nil, err } - addNetworks(kube, KubeGroup, service, names, execStart) + if err := addNetworks(kube, KubeGroup, service, unitsInfoMap, execStart); err != nil { + return nil, err + } updateMaps := kube.LookupAllStrv(KubeGroup, KeyAutoUpdate) for _, update := range updateMaps { @@ -1246,9 +1291,14 @@ func ConvertKube(kube *parser.UnitFile, names map[string]string, isUser bool) (* return service, nil } -func ConvertImage(image *parser.UnitFile) (*parser.UnitFile, string, error) { +func ConvertImage(image *parser.UnitFile, unitsInfoMap map[string]*UnitInfo) (*parser.UnitFile, error) { + unitInfo, ok := unitsInfoMap[image.Filename] + if !ok { + return nil, fmt.Errorf("internal error while processing network %s", image.Filename) + } + service := image.Dup() - service.Filename = replaceExtension(image.Filename, ".service", "", "-image") + service.Filename = unitInfo.ServiceFileName() // Add a dependency on network-online.target so the image pull does not happen // before network is ready @@ -1263,12 +1313,12 @@ func ConvertImage(image *parser.UnitFile) (*parser.UnitFile, string, error) { } if err := checkForUnknownKeys(image, ImageGroup, supportedImageKeys); err != nil { - return nil, "", err + return nil, err } imageName, ok := image.Lookup(ImageGroup, KeyImage) if !ok || len(imageName) == 0 { - return nil, "", fmt.Errorf("no Image key specified") + return nil, fmt.Errorf("no Image key specified") } /* Rename old Network group to x-Network so that systemd ignores it */ @@ -1321,12 +1371,25 @@ func ConvertImage(image *parser.UnitFile) (*parser.UnitFile, string, error) { imageName = name } - return service, imageName, nil + // Store the name of the created resource + unitInfo.ResourceName = imageName + + return service, nil } -func ConvertBuild(build *parser.UnitFile, names map[string]string) (*parser.UnitFile, string, error) { +func ConvertBuild(build *parser.UnitFile, unitsInfoMap map[string]*UnitInfo) (*parser.UnitFile, error) { + unitInfo, ok := unitsInfoMap[build.Filename] + if !ok { + return nil, fmt.Errorf("internal error while processing network %s", build.Filename) + } + + // Fast fail is ResouceName is not set + if len(unitInfo.ResourceName) == 0 { + return nil, fmt.Errorf("no ImageTag key specified") + } + service := build.Dup() - service.Filename = replaceExtension(build.Filename, ".service", "", "-build") + service.Filename = unitInfo.ServiceFileName() // Add a dependency on network-online.target so the image pull does not happen // before network is ready @@ -1347,7 +1410,7 @@ func ConvertBuild(build *parser.UnitFile, names map[string]string) (*parser.Unit } if err := checkForUnknownKeys(build, BuildGroup, supportedBuildKeys); err != nil { - return nil, "", err + return nil, err } podman := createBasePodmanCommand(build, BuildGroup) @@ -1405,22 +1468,19 @@ func ConvertBuild(build *parser.UnitFile, names map[string]string) (*parser.Unit labels := build.LookupAllKeyVal(BuildGroup, KeyLabel) podman.addLabels(labels) - builtImageName, ok := names[build.Filename] - if !ok { - return nil, "", fmt.Errorf("no ImageTag key specified") - } - - podman.addf("--tag=%s", builtImageName) + podman.addf("--tag=%s", unitInfo.ResourceName) - addNetworks(build, BuildGroup, service, names, podman) + if err := addNetworks(build, BuildGroup, service, unitsInfoMap, podman); err != nil { + return nil, err + } secrets := build.LookupAllArgs(BuildGroup, KeySecret) for _, secret := range secrets { podman.add("--secret", secret) } - if err := addVolumes(build, service, BuildGroup, names, podman); err != nil { - return nil, "", err + if err := addVolumes(build, service, BuildGroup, unitsInfoMap, podman); err != nil { + return nil, err } // In order to build an image locally, we need either a File key pointing directly at a @@ -1429,13 +1489,13 @@ func ConvertBuild(build *parser.UnitFile, names map[string]string) (*parser.Unit // an archive. context, err := handleSetWorkingDirectory(build, service, BuildGroup) if err != nil { - return nil, "", err + return nil, err } workingDirectory, okWD := service.Lookup(ServiceGroup, ServiceKeyWorkingDirectory) filePath, okFile := build.Lookup(BuildGroup, KeyFile) if (!okWD || len(workingDirectory) == 0) && (!okFile || len(filePath) == 0) && len(context) == 0 { - return nil, "", fmt.Errorf("neither SetWorkingDirectory, nor File key specified") + return nil, fmt.Errorf("neither SetWorkingDirectory, nor File key specified") } if len(filePath) > 0 { @@ -1450,7 +1510,7 @@ func ConvertBuild(build *parser.UnitFile, names map[string]string) (*parser.Unit } else if !filepath.IsAbs(filePath) && !isURL(filePath) { // Special handling for relative filePaths if len(workingDirectory) == 0 { - return nil, "", fmt.Errorf("relative path in File key requires SetWorkingDirectory key to be set") + return nil, fmt.Errorf("relative path in File key requires SetWorkingDirectory key to be set") } podman.add(workingDirectory) } @@ -1465,7 +1525,7 @@ func ConvertBuild(build *parser.UnitFile, names map[string]string) (*parser.Unit // which isn't very useful here "SyslogIdentifier", "%N") - return service, builtImageName, nil + return service, nil } func GetBuiltImageName(buildUnit *parser.UnitFile) string { @@ -1475,21 +1535,49 @@ func GetBuiltImageName(buildUnit *parser.UnitFile) string { return "" } +func GetContainerServiceName(podUnit *parser.UnitFile) string { + return getServiceName(podUnit, ContainerGroup, "") +} + +func GetKubeServiceName(podUnit *parser.UnitFile) string { + return getServiceName(podUnit, KubeGroup, "") +} + +func GetVolumeServiceName(podUnit *parser.UnitFile) string { + return getServiceName(podUnit, VolumeGroup, "-volume") +} + +func GetNetworkServiceName(podUnit *parser.UnitFile) string { + return getServiceName(podUnit, NetworkGroup, "-network") +} + +func GetImageServiceName(podUnit *parser.UnitFile) string { + return getServiceName(podUnit, ImageGroup, "-image") +} + +func GetBuildServiceName(podUnit *parser.UnitFile) string { + return getServiceName(podUnit, BuildGroup, "-build") +} + func GetPodServiceName(podUnit *parser.UnitFile) string { - if serviceName, ok := podUnit.Lookup(PodGroup, KeyServiceName); ok { + return getServiceName(podUnit, PodGroup, "-pod") +} + +func getServiceName(quadletUnitFile *parser.UnitFile, groupName string, defaultExtraSuffix string) string { + if serviceName, ok := quadletUnitFile.Lookup(groupName, KeyServiceName); ok { return serviceName } - return replaceExtension(podUnit.Filename, "", "", "-pod") + return removeExtension(quadletUnitFile.Filename, "", defaultExtraSuffix) } -func ConvertPod(podUnit *parser.UnitFile, name string, podsInfoMap map[string]*PodInfo, names map[string]string) (*parser.UnitFile, error) { - podInfo, ok := podsInfoMap[podUnit.Filename] +func ConvertPod(podUnit *parser.UnitFile, name string, unitsInfoMap map[string]*UnitInfo) (*parser.UnitFile, error) { + unitInfo, ok := unitsInfoMap[podUnit.Filename] if !ok { return nil, fmt.Errorf("internal error while processing pod %s", podUnit.Filename) } service := podUnit.Dup() - service.Filename = fmt.Sprintf("%s.service", podInfo.ServiceName) + service.Filename = unitInfo.ServiceFileName() if podUnit.Path != "" { service.Add(UnitGroup, "SourcePath", podUnit.Path) @@ -1502,7 +1590,7 @@ func ConvertPod(podUnit *parser.UnitFile, name string, podsInfoMap map[string]*P // Derive pod name from unit name (with added prefix), or use user-provided name. podName, ok := podUnit.Lookup(PodGroup, KeyPodName) if !ok || len(podName) == 0 { - podName = replaceExtension(name, "", "systemd-", "") + podName = removeExtension(name, "systemd-", "") } /* Rename old Pod group to x-Pod so that systemd ignores it */ @@ -1511,7 +1599,7 @@ func ConvertPod(podUnit *parser.UnitFile, name string, podsInfoMap map[string]*P // Need the containers filesystem mounted to start podman service.Add(UnitGroup, "RequiresMountsFor", "%t/containers") - for _, containerService := range podInfo.Containers { + for _, containerService := range unitInfo.Containers { service.Add(UnitGroup, "Wants", containerService) service.Add(UnitGroup, "Before", containerService) } @@ -1555,14 +1643,16 @@ func ConvertPod(podUnit *parser.UnitFile, name string, podsInfoMap map[string]*P return nil, err } - addNetworks(podUnit, PodGroup, service, names, execStartPre) + if err := addNetworks(podUnit, PodGroup, service, unitsInfoMap, execStartPre); err != nil { + return nil, err + } networkAliases := podUnit.LookupAll(PodGroup, KeyNetworkAlias) for _, networkAlias := range networkAliases { execStartPre.add("--network-alias", networkAlias) } - if err := addVolumes(podUnit, service, PodGroup, names, execStartPre); err != nil { + if err := addVolumes(podUnit, service, PodGroup, unitsInfoMap, execStartPre); err != nil { return nil, err } @@ -1714,34 +1804,35 @@ func handleUserRemap(unitFile *parser.UnitFile, groupName string, podman *Podman return nil } -func addNetworks(quadletUnitFile *parser.UnitFile, groupName string, serviceUnitFile *parser.UnitFile, names map[string]string, podman *PodmanCmdline) { +func addNetworks(quadletUnitFile *parser.UnitFile, groupName string, serviceUnitFile *parser.UnitFile, unitsInfoMap map[string]*UnitInfo, podman *PodmanCmdline) error { networks := quadletUnitFile.LookupAll(groupName, KeyNetwork) for _, network := range networks { if len(network) > 0 { quadletNetworkName, options, found := strings.Cut(network, ":") if strings.HasSuffix(quadletNetworkName, ".network") { // the podman network name is systemd-$name if none is specified by the user. - networkName := names[quadletNetworkName] - if networkName == "" { - networkName = replaceExtension(quadletNetworkName, "", "systemd-", "") + networkUnitInfo, ok := unitsInfoMap[quadletNetworkName] + if !ok { + return fmt.Errorf("requested Quadlet image %s was not found", quadletNetworkName) } - // the systemd unit name is $name-network.service - networkServiceName := replaceExtension(quadletNetworkName, ".service", "", "-network") + // the systemd unit name is $serviceName.service + networkServiceName := networkUnitInfo.ServiceFileName() serviceUnitFile.Add(UnitGroup, "Requires", networkServiceName) serviceUnitFile.Add(UnitGroup, "After", networkServiceName) if found { - network = fmt.Sprintf("%s:%s", networkName, options) + network = fmt.Sprintf("%s:%s", networkUnitInfo.ResourceName, options) } else { - network = networkName + network = networkUnitInfo.ResourceName } } podman.addf("--network=%s", network) } } + return nil } // Systemd Specifiers start with % with the exception of %% @@ -1851,7 +1942,7 @@ func handleLogOpt(unitFile *parser.UnitFile, groupName string, podman *PodmanCmd } } -func handleStorageSource(quadletUnitFile, serviceUnitFile *parser.UnitFile, source string, names map[string]string) (string, error) { +func handleStorageSource(quadletUnitFile, serviceUnitFile *parser.UnitFile, source string, unitsInfoMap map[string]*UnitInfo) (string, error) { if source[0] == '.' { var err error source, err = getAbsolutePath(quadletUnitFile, source) @@ -1863,19 +1954,17 @@ func handleStorageSource(quadletUnitFile, serviceUnitFile *parser.UnitFile, sour // Absolute path serviceUnitFile.Add(UnitGroup, "RequiresMountsFor", source) } else if strings.HasSuffix(source, ".volume") { - // the podman volume name is systemd-$name if none has been provided by the user. - volumeName := names[source] - if volumeName == "" { - volumeName = replaceExtension(source, "", "systemd-", "") + volumeUnitInfo, ok := unitsInfoMap[source] + if !ok { + return "", fmt.Errorf("requested Quadlet image %s was not found", source) } - // the systemd unit name is $name-volume.service - volumeServiceName := replaceExtension(source, ".service", "", "-volume") - - source = volumeName - + // the systemd unit name is $serviceName.service + volumeServiceName := volumeUnitInfo.ServiceFileName() serviceUnitFile.Add(UnitGroup, "Requires", volumeServiceName) serviceUnitFile.Add(UnitGroup, "After", volumeServiceName) + + source = volumeUnitInfo.ResourceName } return source, nil @@ -1989,29 +2078,29 @@ func lookupAndAddBoolean(unit *parser.UnitFile, group, key, flag string, podman } } -func handleImageSource(quadletImageName string, serviceUnitFile *parser.UnitFile, names map[string]string) (string, error) { +func handleImageSource(quadletImageName string, serviceUnitFile *parser.UnitFile, unitsInfoMap map[string]*UnitInfo) (string, error) { for _, suffix := range []string{".build", ".image"} { if strings.HasSuffix(quadletImageName, suffix) { // since there is no default name conversion, the actual image name must exist in the names map - imageName, ok := names[quadletImageName] + unitInfo, ok := unitsInfoMap[quadletImageName] if !ok { return "", fmt.Errorf("requested Quadlet image %s was not found", quadletImageName) } // the systemd unit name is $name-$suffix.service - imageServiceName := replaceExtension(quadletImageName, ".service", "", fmt.Sprintf("-%s", suffix[1:])) + imageServiceName := unitInfo.ServiceFileName() serviceUnitFile.Add(UnitGroup, "Requires", imageServiceName) serviceUnitFile.Add(UnitGroup, "After", imageServiceName) - quadletImageName = imageName + quadletImageName = unitInfo.ResourceName } } return quadletImageName, nil } -func resolveContainerMountParams(containerUnitFile, serviceUnitFile *parser.UnitFile, mount string, names map[string]string) (string, error) { +func resolveContainerMountParams(containerUnitFile, serviceUnitFile *parser.UnitFile, mount string, unitsInfoMap map[string]*UnitInfo) (string, error) { mountType, tokens, err := specgenutilexternal.FindMountType(mount) if err != nil { return "", err @@ -2035,7 +2124,7 @@ func resolveContainerMountParams(containerUnitFile, serviceUnitFile *parser.Unit } } - resolvedSource, err := handleStorageSource(containerUnitFile, serviceUnitFile, originalSource, names) + resolvedSource, err := handleStorageSource(containerUnitFile, serviceUnitFile, originalSource, unitsInfoMap) if err != nil { return "", err } @@ -2080,21 +2169,21 @@ func createBasePodmanCommand(unitFile *parser.UnitFile, groupName string) *Podma return podman } -func handlePod(quadletUnitFile, serviceUnitFile *parser.UnitFile, groupName string, podsInfoMap map[string]*PodInfo, podman *PodmanCmdline) error { +func handlePod(quadletUnitFile, serviceUnitFile *parser.UnitFile, groupName string, unitsInfoMap map[string]*UnitInfo, podman *PodmanCmdline) error { pod, ok := quadletUnitFile.Lookup(groupName, KeyPod) if ok && len(pod) > 0 { if !strings.HasSuffix(pod, ".pod") { return fmt.Errorf("pod %s is not Quadlet based", pod) } - podInfo, ok := podsInfoMap[pod] + podInfo, ok := unitsInfoMap[pod] if !ok { return fmt.Errorf("quadlet pod unit %s does not exist", pod) } podman.add("--pod-id-file", fmt.Sprintf("%%t/%s.pod-id", podInfo.ServiceName)) - podServiceName := fmt.Sprintf("%s.service", podInfo.ServiceName) + podServiceName := podInfo.ServiceFileName() serviceUnitFile.Add(UnitGroup, "BindsTo", podServiceName) serviceUnitFile.Add(UnitGroup, "After", podServiceName) @@ -2103,7 +2192,7 @@ func handlePod(quadletUnitFile, serviceUnitFile *parser.UnitFile, groupName stri return nil } -func addVolumes(quadletUnitFile, serviceUnitFile *parser.UnitFile, groupName string, names map[string]string, podman *PodmanCmdline) error { +func addVolumes(quadletUnitFile, serviceUnitFile *parser.UnitFile, groupName string, unitsInfoMap map[string]*UnitInfo, podman *PodmanCmdline) error { volumes := quadletUnitFile.LookupAll(groupName, KeyVolume) for _, volume := range volumes { parts := strings.SplitN(volume, ":", 3) @@ -2123,7 +2212,7 @@ func addVolumes(quadletUnitFile, serviceUnitFile *parser.UnitFile, groupName str if source != "" { var err error - source, err = handleStorageSource(quadletUnitFile, serviceUnitFile, source, names) + source, err = handleStorageSource(quadletUnitFile, serviceUnitFile, source, unitsInfoMap) if err != nil { return err } diff --git a/test/e2e/quadlet/build.quadlet.servicename.volume b/test/e2e/quadlet/build.quadlet.servicename.volume new file mode 100644 index 0000000000..c3e6a92084 --- /dev/null +++ b/test/e2e/quadlet/build.quadlet.servicename.volume @@ -0,0 +1,8 @@ +## assert-podman-args --driver=image +## assert-podman-args --opt image=localhost/imagename +## assert-key-is "Unit" "Requires" "basic.service" +## assert-key-is "Unit" "After" "basic.service" + +[Volume] +Driver=image +Image=service-name.build diff --git a/test/e2e/quadlet/image.quadlet.servicename.volume b/test/e2e/quadlet/image.quadlet.servicename.volume new file mode 100644 index 0000000000..43d4a8f786 --- /dev/null +++ b/test/e2e/quadlet/image.quadlet.servicename.volume @@ -0,0 +1,8 @@ +## assert-podman-args --driver=image +## assert-podman-args --opt image=localhost/imagename +## assert-key-is "Unit" "Requires" "basic.service" +## assert-key-is "Unit" "After" "basic.service" + +[Volume] +Driver=image +Image=service-name.image diff --git a/test/e2e/quadlet/mount.container b/test/e2e/quadlet/mount.container index 9969571bb1..bd156dc72b 100644 --- a/test/e2e/quadlet/mount.container +++ b/test/e2e/quadlet/mount.container @@ -8,10 +8,10 @@ Mount=type=bind,src=/path/on/host,dst=/path/in/container,relabel=shared Mount=type=bind,src=/path/on/host,dst=/path/in/container,relabel=shared,U=true ## assert-podman-args-key-val "--mount" "," "type=volume,source=vol1,destination=/path/in/container,ro=true" Mount=type=volume,source=vol1,destination=/path/in/container,ro=true -## assert-podman-args-key-val "--mount" "," "type=volume,source=systemd-vol2,destination=/path/in/container,ro=true" -## assert-key-is "Unit" "Requires" "vol2-volume.service" -## assert-key-is "Unit" "After" "network-online.target" "vol2-volume.service" -Mount=type=volume,source=vol2.volume,destination=/path/in/container,ro=true +## assert-podman-args-key-val "--mount" "," "type=volume,source=systemd-basic,destination=/path/in/container,ro=true" +## assert-key-is "Unit" "Requires" "basic-volume.service" +## assert-key-is "Unit" "After" "network-online.target" "basic-volume.service" +Mount=type=volume,source=basic.volume,destination=/path/in/container,ro=true ## assert-podman-args-key-val "--mount" "," "type=tmpfs,tmpfs-size=512M,destination=/path/in/container" Mount=type=tmpfs,tmpfs-size=512M,destination=/path/in/container ## assert-podman-args-key-val "--mount" "," "type=image,source=fedora,destination=/fedora-image,rw=true" diff --git a/test/e2e/quadlet/mount.servicename.container b/test/e2e/quadlet/mount.servicename.container new file mode 100644 index 0000000000..95be8f82af --- /dev/null +++ b/test/e2e/quadlet/mount.servicename.container @@ -0,0 +1,6 @@ +[Container] +Image=localhost/imagename +## assert-podman-args-key-val "--mount" "," "type=volume,source=test-volume,destination=/path/in/container,ro=true" +## assert-key-is "Unit" "Requires" "basic.service" +## assert-key-is "Unit" "After" "network-online.target" "basic.service" +Mount=type=volume,source=service-name.volume,destination=/path/in/container,ro=true diff --git a/test/e2e/quadlet/network.quadlet.servicename.build b/test/e2e/quadlet/network.quadlet.servicename.build new file mode 100644 index 0000000000..5e458028a4 --- /dev/null +++ b/test/e2e/quadlet/network.quadlet.servicename.build @@ -0,0 +1,8 @@ +## assert-podman-args "--network=test-network" +## assert-key-is "Unit" "Requires" "basic.service" +## assert-key-is "Unit" "After" "network-online.target" "basic.service" + +[Build] +ImageTag=localhost/imagename +SetWorkingDirectory=unit +Network=service-name.network diff --git a/test/e2e/quadlet/network.quadlet.servicename.container b/test/e2e/quadlet/network.quadlet.servicename.container new file mode 100644 index 0000000000..f4d2dc80a6 --- /dev/null +++ b/test/e2e/quadlet/network.quadlet.servicename.container @@ -0,0 +1,7 @@ +## assert-podman-args "--network=test-network" +## assert-key-is "Unit" "Requires" "basic.service" +## assert-key-is "Unit" "After" "network-online.target" "basic.service" + +[Container] +Image=localhost/imagename +Network=service-name.network diff --git a/test/e2e/quadlet/network.quadlet.servicename.kube b/test/e2e/quadlet/network.quadlet.servicename.kube new file mode 100644 index 0000000000..f72646ab90 --- /dev/null +++ b/test/e2e/quadlet/network.quadlet.servicename.kube @@ -0,0 +1,8 @@ +## assert-podman-args "--network=test-network" +## assert-key-is "Unit" "Requires" "basic.service" +## assert-key-is "Unit" "After" "basic.service" + + +[Kube] +Yaml=deployment.yml +Network=service-name.network diff --git a/test/e2e/quadlet/network.servicename.quadlet.pod b/test/e2e/quadlet/network.servicename.quadlet.pod new file mode 100644 index 0000000000..8f0cf9810c --- /dev/null +++ b/test/e2e/quadlet/network.servicename.quadlet.pod @@ -0,0 +1,6 @@ +## assert-podman-pre-args "--network=test-network" +## assert-key-is "Unit" "Requires" "basic.service" +## assert-key-is "Unit" "After" "basic.service" + +[Pod] +Network=service-name.network diff --git a/test/e2e/quadlet/service-name.build b/test/e2e/quadlet/service-name.build new file mode 100644 index 0000000000..6f6581023d --- /dev/null +++ b/test/e2e/quadlet/service-name.build @@ -0,0 +1,6 @@ +## assert-podman-args --tag=localhost/imagename + +[Build] +ServiceName=basic +ImageTag=localhost/imagename +SetWorkingDirectory=unit diff --git a/test/e2e/quadlet/service-name.container b/test/e2e/quadlet/service-name.container new file mode 100644 index 0000000000..d58163282b --- /dev/null +++ b/test/e2e/quadlet/service-name.container @@ -0,0 +1,5 @@ +## assert-podman-final-args localhost/imagename + +[Container] +ServiceName=basic +Image=localhost/imagename diff --git a/test/e2e/quadlet/service-name.image b/test/e2e/quadlet/service-name.image new file mode 100644 index 0000000000..a22c25dd1a --- /dev/null +++ b/test/e2e/quadlet/service-name.image @@ -0,0 +1,5 @@ +## assert-podman-final-args localhost/imagename + +[Image] +ServiceName=basic +Image=localhost/imagename diff --git a/test/e2e/quadlet/service-name.kube b/test/e2e/quadlet/service-name.kube new file mode 100644 index 0000000000..13500acaf5 --- /dev/null +++ b/test/e2e/quadlet/service-name.kube @@ -0,0 +1,5 @@ +## assert-podman-final-args-regex .*/podman-e2e-.*/subtest-.*/quadlet/deployment.yml + +[Kube] +ServiceName=basic +Yaml=deployment.yml diff --git a/test/e2e/quadlet/service-name.network b/test/e2e/quadlet/service-name.network new file mode 100644 index 0000000000..1efda88bf3 --- /dev/null +++ b/test/e2e/quadlet/service-name.network @@ -0,0 +1,5 @@ +## assert-podman-final-args "test-network" + +[Network] +ServiceName=basic +NetworkName=test-network diff --git a/test/e2e/quadlet/service-name.pod b/test/e2e/quadlet/service-name.pod index 6f2842e083..353309a592 100644 --- a/test/e2e/quadlet/service-name.pod +++ b/test/e2e/quadlet/service-name.pod @@ -1,5 +1,5 @@ ## assert-podman-pre-args "--name=test-pod" [Pod] +ServiceName=basic PodName=test-pod -ServiceName=test-pod diff --git a/test/e2e/quadlet/service-name.volume b/test/e2e/quadlet/service-name.volume new file mode 100644 index 0000000000..59071822fd --- /dev/null +++ b/test/e2e/quadlet/service-name.volume @@ -0,0 +1,5 @@ +## assert-podman-final-args "test-volume" + +[Volume] +ServiceName=basic +VolumeName=test-volume diff --git a/test/e2e/quadlet/volume.build b/test/e2e/quadlet/volume.build index f63ac66fc6..bcbbf37157 100644 --- a/test/e2e/quadlet/volume.build +++ b/test/e2e/quadlet/volume.build @@ -2,7 +2,7 @@ ## assert-podman-args -v /host/dir2:/container/volume2:Z ## assert-podman-args-regex -v .*/podman-e2e-.*/subtest-.*/quadlet/host/dir3:/container/volume3 ## assert-podman-args -v named:/container/named -## assert-podman-args -v systemd-quadlet:/container/quadlet +## assert-podman-args -v systemd-basic:/container/quadlet ## assert-podman-args -v %h/container:/container/volume4 [Build] @@ -13,5 +13,5 @@ Volume=/host/dir2:/container/volume2:Z Volume=./host/dir3:/container/volume3 Volume=/container/empty Volume=named:/container/named -Volume=quadlet.volume:/container/quadlet +Volume=basic.volume:/container/quadlet Volume=%h/container:/container/volume4 diff --git a/test/e2e/quadlet/volume.container b/test/e2e/quadlet/volume.container index b3d033c6f8..1e6e884111 100644 --- a/test/e2e/quadlet/volume.container +++ b/test/e2e/quadlet/volume.container @@ -2,7 +2,7 @@ ## assert-podman-args -v /host/dir2:/container/volume2:Z ## assert-podman-args-regex -v .*/podman-e2e-.*/subtest-.*/quadlet/host/dir3:/container/volume3 ## assert-podman-args -v named:/container/named -## assert-podman-args -v systemd-quadlet:/container/quadlet +## assert-podman-args -v systemd-basic:/container/quadlet ## assert-podman-args -v %h/container:/container/volume4 [Container] @@ -12,5 +12,5 @@ Volume=/host/dir2:/container/volume2:Z Volume=./host/dir3:/container/volume3 Volume=/container/empty Volume=named:/container/named -Volume=quadlet.volume:/container/quadlet +Volume=basic.volume:/container/quadlet Volume=%h/container:/container/volume4 diff --git a/test/e2e/quadlet/volume.pod b/test/e2e/quadlet/volume.pod index b2fa6117fa..1c1b6578df 100644 --- a/test/e2e/quadlet/volume.pod +++ b/test/e2e/quadlet/volume.pod @@ -2,7 +2,7 @@ ## assert-podman-pre-args -v /host/dir2:/container/volume2:Z ## assert-podman-pre-args-regex -v .*/podman-e2e-.*/subtest-.*/quadlet/host/dir3:/container/volume3 ## assert-podman-pre-args -v named:/container/named -## assert-podman-pre-args -v systemd-quadlet:/container/quadlet +## assert-podman-pre-args -v systemd-basic:/container/quadlet ## assert-podman-pre-args -v %h/container:/container/volume4 [Pod] @@ -11,5 +11,5 @@ Volume=/host/dir2:/container/volume2:Z Volume=./host/dir3:/container/volume3 Volume=/container/empty Volume=named:/container/named -Volume=quadlet.volume:/container/quadlet +Volume=basic.volume:/container/quadlet Volume=%h/container:/container/volume4 diff --git a/test/e2e/quadlet/volume.quadlet.servicename.build b/test/e2e/quadlet/volume.quadlet.servicename.build new file mode 100644 index 0000000000..d33df93335 --- /dev/null +++ b/test/e2e/quadlet/volume.quadlet.servicename.build @@ -0,0 +1,8 @@ +## assert-podman-args "-v" "test-volume:/volume/basic" +## assert-key-is "Unit" "Requires" "basic.service" +## assert-key-is "Unit" "After" "network-online.target" "basic.service" + +[Build] +ImageTag=localhost/imagename +SetWorkingDirectory=unit +Volume=service-name.volume:/volume/basic diff --git a/test/e2e/quadlet/volume.servicename.container b/test/e2e/quadlet/volume.servicename.container new file mode 100644 index 0000000000..dece6a4af3 --- /dev/null +++ b/test/e2e/quadlet/volume.servicename.container @@ -0,0 +1,6 @@ +[Container] +Image=localhost/imagename +## assert-key-is "Unit" "Requires" "basic.service" +## assert-key-is "Unit" "After" "network-online.target" "basic.service" +## assert-podman-args -v test-volume:/container/quadlet +Volume=service-name.volume:/container/quadlet diff --git a/test/e2e/quadlet/volume.servicename.pod b/test/e2e/quadlet/volume.servicename.pod new file mode 100644 index 0000000000..07e64c4539 --- /dev/null +++ b/test/e2e/quadlet/volume.servicename.pod @@ -0,0 +1,6 @@ +## assert-podman-pre-args -v test-volume:/container/quadlet +## assert-key-is "Unit" "Requires" "basic.service" +## assert-key-is "Unit" "After" "basic.service" + +[Pod] +Volume=service-name.volume:/container/quadlet diff --git a/test/e2e/quadlet_test.go b/test/e2e/quadlet_test.go index 1814cd55e6..e93b20eb6f 100644 --- a/test/e2e/quadlet_test.go +++ b/test/e2e/quadlet_test.go @@ -36,10 +36,7 @@ func getGenericTemplateFile(fileName string) (bool, string) { return false, "" } -func loadQuadletTestcase(path string) *quadletTestcase { - data, err := os.ReadFile(path) - Expect(err).ToNot(HaveOccurred()) - +func calcServiceName(path string) string { base := filepath.Base(path) ext := filepath.Ext(base) service := base[:len(base)-len(ext)] @@ -55,6 +52,23 @@ func loadQuadletTestcase(path string) *quadletTestcase { case ".pod": service += "-pod" } + return service +} + +func loadQuadletTestcase(path string) *quadletTestcase { + return loadQuadletTestcaseWithServiceName(path, "") +} + +func loadQuadletTestcaseWithServiceName(path, serviceName string) *quadletTestcase { + data, err := os.ReadFile(path) + Expect(err).ToNot(HaveOccurred()) + + var service string + if len(serviceName) > 0 { + service = serviceName + } else { + service = calcServiceName(path) + } service += ".service" checks := make([][]string, 0) @@ -609,8 +623,8 @@ var _ = Describe("quadlet system generator", func() { generatedDir string quadletDir string - runQuadletTestCase = func(fileName string, exitCode int, errString string) { - testcase := loadQuadletTestcase(filepath.Join("quadlet", fileName)) + runQuadletTestCaseWithServiceName = func(fileName string, exitCode int, errString string, serviceName string) { + testcase := loadQuadletTestcaseWithServiceName(filepath.Join("quadlet", fileName), serviceName) // Write the tested file to the quadlet dir err = os.WriteFile(filepath.Join(quadletDir, fileName), testcase.data, 0644) @@ -647,6 +661,10 @@ var _ = Describe("quadlet system generator", func() { testcase.check(generatedDir, session) } + runQuadletTestCase = func(fileName string, exitCode int, errString string) { + runQuadletTestCaseWithServiceName(fileName, exitCode, errString, "") + } + runSuccessQuadletTestCase = func(fileName string) { runQuadletTestCase(fileName, 0, "") } @@ -831,11 +849,9 @@ BOGUS=foo Entry("logdriver.container", "logdriver.container"), Entry("logopt.container", "logopt.container"), Entry("mask.container", "mask.container"), - Entry("mount.container", "mount.container"), Entry("name.container", "name.container"), Entry("nestedselinux.container", "nestedselinux.container"), Entry("network.container", "network.container"), - Entry("network.quadlet.container", "network.quadlet.container"), Entry("notify.container", "notify.container"), Entry("notify-healthy.container", "notify-healthy.container"), Entry("oneshot.container", "oneshot.container"), @@ -870,7 +886,6 @@ BOGUS=foo Entry("unmask.container", "unmask.container"), Entry("user.container", "user.container"), Entry("userns.container", "userns.container"), - Entry("volume.container", "volume.container"), Entry("workingdir.container", "workingdir.container"), Entry("Container - global args", "globalargs.container"), Entry("Container - Containers Conf Modules", "containersconfmodule.container"), @@ -902,7 +917,6 @@ BOGUS=foo Entry("Kube - PodmanArgs", "podmanargs.kube"), Entry("Kube - Publish IPv4 ports", "ports.kube"), Entry("Kube - Publish IPv6 ports", "ports_ipv6.kube"), - Entry("Kube - Quadlet Network", "network.quadlet.kube"), Entry("Kube - User Remap Auto with IDs", "remap-auto2.kube"), Entry("Kube - User Remap Auto", "remap-auto.kube"), Entry("Syslog Identifier", "syslog.identifier.kube"), @@ -967,7 +981,6 @@ BOGUS=foo Entry("Build - Containers Conf Modules", "containersconfmodule.build"), Entry("Build - Label Key", "label.build"), Entry("Build - Network Key host", "network.build"), - Entry("Build - Network Key quadlet", "network.quadlet.build"), Entry("Build - PodmanArgs", "podmanargs.build"), Entry("Build - Pull Key", "pull.build"), Entry("Build - Secrets", "secrets.build"), @@ -982,15 +995,11 @@ BOGUS=foo Entry("Build - Target Key", "target.build"), Entry("Build - TLSVerify Key", "tls-verify.build"), Entry("Build - Variant Key", "variant.build"), - Entry("Build - Volume Key", "volume.build"), - Entry("Build - Volume Key quadlet", "volume.quadlet.build"), Entry("basic.pod", "basic.pod"), Entry("name.pod", "name.pod"), Entry("network.pod", "network.pod"), - Entry("network-quadlet.pod", "network.quadlet.pod"), Entry("podmanargs.pod", "podmanargs.pod"), - Entry("volume.pod", "volume.pod"), Entry("Pod - NetworkAlias", "network-alias.pod"), ) @@ -1026,8 +1035,21 @@ BOGUS=foo Entry("Build - No ImageTag Key", "no-imagetag.build", "converting \"no-imagetag.build\": no ImageTag key specified"), ) - DescribeTable("Running quadlet test case with dependencies", - func(fileName string, exitCode int, errString string, dependencyFiles []string) { + DescribeTable("Running success quadlet with ServiceName test case", + func(fileName, serviceName string) { + runQuadletTestCaseWithServiceName(fileName, 0, "", serviceName) + }, + Entry("Build", "service-name.build", "basic"), + Entry("Container", "service-name.container", "basic"), + Entry("Image", "service-name.image", "basic"), + Entry("Kube", "service-name.kube", "basic"), + Entry("Network", "service-name.network", "basic"), + Entry("Pod", "service-name.pod", "basic"), + Entry("Volume", "service-name.volume", "basic"), + ) + + DescribeTable("Running quadlet success test case with dependencies", + func(fileName string, dependencyFiles []string) { // Write additional files this test depends on to the quadlet dir for _, dependencyFileName := range dependencyFiles { dependencyTestCase := loadQuadletTestcase(filepath.Join("quadlet", dependencyFileName)) @@ -1035,10 +1057,33 @@ BOGUS=foo Expect(err).ToNot(HaveOccurred()) } - runQuadletTestCase(fileName, exitCode, errString) + runSuccessQuadletTestCase(fileName) }, - Entry("Volume - Quadlet image (.build)", "build.quadlet.volume", 0, "", []string{"basic.build"}), - Entry("Volume - Quadlet image (.image)", "image.quadlet.volume", 0, "", []string{"basic.image"}), + Entry("Container - Mount", "mount.container", []string{"basic.volume"}), + Entry("Container - Quadlet Network", "network.quadlet.container", []string{"basic.network"}), + Entry("Container - Quadlet Volume", "volume.container", []string{"basic.volume"}), + Entry("Container - Mount overriding service name", "mount.servicename.container", []string{"service-name.volume"}), + Entry("Container - Quadlet Network overriding service name", "network.quadlet.servicename.container", []string{"service-name.network"}), + Entry("Container - Quadlet Volume overriding service name", "volume.servicename.container", []string{"service-name.volume"}), + + Entry("Volume - Quadlet image (.build)", "build.quadlet.volume", []string{"basic.build"}), + Entry("Volume - Quadlet image (.image)", "image.quadlet.volume", []string{"basic.image"}), + Entry("Volume - Quadlet image (.build) overriding service name", "build.quadlet.servicename.volume", []string{"service-name.build"}), + Entry("Volume - Quadlet image (.image) overriding service name", "image.quadlet.servicename.volume", []string{"service-name.image"}), + + Entry("Kube - Quadlet Network", "network.quadlet.kube", []string{"basic.network"}), + Entry("Kube - Quadlet Network overriding service name", "network.quadlet.servicename.kube", []string{"service-name.network"}), + + Entry("Build - Network Key quadlet", "network.quadlet.build", []string{"basic.network"}), + Entry("Build - Volume Key", "volume.build", []string{"basic.volume"}), + Entry("Build - Volume Key quadlet", "volume.quadlet.build", []string{"basic.volume"}), + Entry("Build - Network Key quadlet overriding service name", "network.quadlet.servicename.build", []string{"service-name.network"}), + Entry("Build - Volume Key quadlet overriding service name", "volume.quadlet.servicename.build", []string{"service-name.volume"}), + + Entry("Pod - Quadlet Network", "network.quadlet.pod", []string{"basic.network"}), + Entry("Pod - Quadlet Volume", "volume.pod", []string{"basic.volume"}), + Entry("Pod - Quadlet Network overriding service name", "network.servicename.quadlet.pod", []string{"service-name.network"}), + Entry("Pod - Quadlet Volume overriding service name", "volume.servicename.pod", []string{"service-name.volume"}), ) }) diff --git a/test/system/252-quadlet.bats b/test/system/252-quadlet.bats index 8d8494d35a..90677763c5 100644 --- a/test/system/252-quadlet.bats +++ b/test/system/252-quadlet.bats @@ -383,8 +383,9 @@ EOF [Volume] EOF + local quadlet_tmpdir=$(mktemp -d --tmpdir=$PODMAN_TMPDIR quadlet.XXXXXX) # Have quadlet create the systemd unit file for the volume unit - run_quadlet "$quadlet_vol_file" + run_quadlet "$quadlet_vol_file" "$quadlet_tmpdir" # Save the volume service name since the variable will be overwritten local vol_service=$QUADLET_SERVICE_NAME @@ -399,7 +400,7 @@ Volume=$quadlet_vol_unit:/tmp EOF # Have quadlet create the systemd unit file for the container unit - run_quadlet "$quadlet_file" + run_quadlet "$quadlet_file" "$quadlet_tmpdir" # Save the container service name for readability local container_service=$QUADLET_SERVICE_NAME @@ -510,8 +511,9 @@ EOF [Network] EOF + local quadlet_tmpdir=$(mktemp -d --tmpdir=$PODMAN_TMPDIR quadlet.XXXXXX) # Have quadlet create the systemd unit file for the network unit - run_quadlet "$quadlet_network_file" + run_quadlet "$quadlet_network_file" "$quadlet_tmpdir" # Save the volume service name since the variable will be overwritten local network_service=$QUADLET_SERVICE_NAME @@ -525,7 +527,7 @@ Exec=top Network=$quadlet_network_unit EOF - run_quadlet "$quadlet_file" + run_quadlet "$quadlet_file" "$quadlet_tmpdir" # Save the container service name for readability local container_service=$QUADLET_SERVICE_NAME