From cf505fe788b2834f9087f9a3583f45121e8bb3fa Mon Sep 17 00:00:00 2001 From: Misaki Kasumi Date: Sat, 7 Dec 2024 22:57:00 +0800 Subject: [PATCH] quadlet: fix inter-dependency of containers in `Network=` Signed-off-by: Misaki Kasumi --- cmd/quadlet/main.go | 2 + pkg/systemd/quadlet/quadlet.go | 41 +++++++++++++------ test/e2e/quadlet/a.network.reuse.container | 7 ++++ .../quadlet/a.network.reuse.name.container | 7 ++++ test/e2e/quadlet_test.go | 2 + 5 files changed, 46 insertions(+), 13 deletions(-) create mode 100644 test/e2e/quadlet/a.network.reuse.container create mode 100644 test/e2e/quadlet/a.network.reuse.name.container diff --git a/cmd/quadlet/main.go b/cmd/quadlet/main.go index bf584c10c9..77e522f672 100644 --- a/cmd/quadlet/main.go +++ b/cmd/quadlet/main.go @@ -591,6 +591,8 @@ func generateUnitsInfoMap(units []*parser.UnitFile) map[string]*quadlet.UnitInfo switch { case strings.HasSuffix(unit.Filename, ".container"): serviceName = quadlet.GetContainerServiceName(unit) + // Prefill resouceNames for .container files. This solves network reusing. + resourceName = quadlet.GetContainerResourceName(unit) case strings.HasSuffix(unit.Filename, ".volume"): serviceName = quadlet.GetVolumeServiceName(unit) case strings.HasSuffix(unit.Filename, ".kube"): diff --git a/pkg/systemd/quadlet/quadlet.go b/pkg/systemd/quadlet/quadlet.go index 5fdbdda5ca..79f65c42f8 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,37 @@ func ConvertContainer(container *parser.UnitFile, isUser bool, unitsInfoMap map[ service.AddCmdline(ServiceGroup, "ExecStart", podman.Args) + 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) string { + 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) + resourceName := strings.ReplaceAll(containerName, "%N", GetContainerServiceName(container)) + if !strings.Contains(resourceName, "%") { - unitInfo.ResourceName = resourceName + return resourceName + } else { + return "" } - - return service, nil } func defaultOneshotServiceGroup(service *parser.UnitFile, remainAfterExit bool) { diff --git a/test/e2e/quadlet/a.network.reuse.container b/test/e2e/quadlet/a.network.reuse.container new file mode 100644 index 0000000000..f9a6f6b142 --- /dev/null +++ b/test/e2e/quadlet/a.network.reuse.container @@ -0,0 +1,7 @@ +## assert-podman-args "--network" "container:systemd-basic" +## assert-key-is "Unit" "Requires" "basic.service" +## assert-key-is-regex "Unit" "After" "network-online.target|podman-user-wait-network-online.service" "basic.service" + +[Container] +Image=localhost/imagename +Network=basic.container diff --git a/test/e2e/quadlet/a.network.reuse.name.container b/test/e2e/quadlet/a.network.reuse.name.container new file mode 100644 index 0000000000..2927e6fea0 --- /dev/null +++ b/test/e2e/quadlet/a.network.reuse.name.container @@ -0,0 +1,7 @@ +## assert-podman-args "--network" "container:foobar" +## assert-key-is "Unit" "Requires" "name.service" +## assert-key-is-regex "Unit" "After" "network-online.target|podman-user-wait-network-online.service" "name.service" + +[Container] +Image=localhost/imagename +Network=name.container diff --git a/test/e2e/quadlet_test.go b/test/e2e/quadlet_test.go index 271998fc7d..d896f6433c 100644 --- a/test/e2e/quadlet_test.go +++ b/test/e2e/quadlet_test.go @@ -1109,6 +1109,8 @@ BOGUS=foo Entry("Container - Quadlet build with multiple tags", "build.multiple-tags.container", []string{"multiple-tags.build"}), Entry("Container - Reuse another container's network", "network.reuse.container", []string{"basic.container"}), Entry("Container - Reuse another named container's network", "network.reuse.name.container", []string{"name.container"}), + Entry("Container - Reuse another container's network", "a.network.reuse.container", []string{"basic.container"}), + Entry("Container - Reuse another named container's network", "a.network.reuse.name.container", []string{"name.container"}), Entry("Volume - Quadlet image (.build)", "build.quadlet.volume", []string{"basic.build"}), Entry("Volume - Quadlet image (.image)", "image.quadlet.volume", []string{"basic.image"}),