Quadlet: Add support for .build files

.build files allow to build an image via Quadlet. The keys from a .build
file are translated to arguments of a `podman build` command by Quadlet.

Minimal keys for .build files are `ImageTag=` and a context directory,
see `SetWorkingDirectory=`, or a `File=` pointing to a Containerfile.

After sorting .build files into the Quadlet dependency order, there
remains a possible dependency cycle issue between .volume and .build
files: A .volume can have `Image=some.build`, and a .build can have
`Volume=some.volume:/some/volume`.

We solve this dependency cycle by prefilling resourceNames with all
image names from .build files before converting all the unit files.

This results in an issue for the test suite though: For .volume's
depending on *.image or *.build, we need to copy these additional
dependencies to the test's quadletDir, otherwise the test will fail.
This is necessary, because `handleImageSource()` actually needs to know
the image name defined in the referenced *.{build,image} file. It cannot
fall back on the default names, as it is done for networks or volumes,
for example.

Signed-off-by: Johannes Maibaum <jmaibaum@gmail.com>
This commit is contained in:
Johannes Maibaum
2024-05-14 00:09:46 +02:00
parent 7ec22abb1c
commit 9f823ecb25
45 changed files with 985 additions and 79 deletions

View File

@ -49,12 +49,13 @@ var (
// Key: Extension
// Value: Processing order for resource naming dependencies
supportedExtensions = map[string]int{
".container": 3,
".container": 4,
".volume": 2,
".kube": 3,
".kube": 4,
".network": 2,
".image": 1,
".pod": 4,
".build": 3,
".pod": 5,
}
)
@ -474,7 +475,7 @@ func warnIfAmbiguousName(unit *parser.UnitFile, group string) {
if !ok {
return
}
if strings.HasSuffix(imageName, ".image") {
if strings.HasSuffix(imageName, ".build") || strings.HasSuffix(imageName, ".image") {
return
}
if !isUnambiguousName(imageName) {
@ -499,6 +500,19 @@ func generatePodsInfoMap(units []*parser.UnitFile) map[string]*quadlet.PodInfo {
return podsInfoMap
}
func prefillBuiltImageNames(units []*parser.UnitFile, resourceNames map[string]string) {
for _, unit := range units {
if !strings.HasSuffix(unit.Filename, ".build") {
continue
}
imageName := quadlet.GetBuiltImageName(unit)
if len(imageName) > 0 {
resourceNames[unit.Filename] = imageName
}
}
}
func main() {
if err := process(); err != nil {
Logf("%s", err.Error())
@ -600,6 +614,12 @@ func process() error {
// 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)
for _, unit := range units {
var service *parser.UnitFile
var name string
@ -619,6 +639,8 @@ func process() error {
case strings.HasSuffix(unit.Filename, ".image"):
warnIfAmbiguousName(unit, quadlet.ImageGroup)
service, name, err = quadlet.ConvertImage(unit)
case strings.HasSuffix(unit.Filename, ".build"):
service, name, err = quadlet.ConvertBuild(unit, resourceNames)
case strings.HasSuffix(unit.Filename, ".pod"):
service, err = quadlet.ConvertPod(unit, unit.Filename, podsInfoMap, resourceNames)
default: