Correct `generate kube` on containers userns annotation

The `podman generate kube` command on containers follows a
different codepath from pods. Pods store a lot of pod-level
configuration - including user namespace information - in
annotations, so it can be restored by `play kube`. Generating for
a container does not do the same thing, because we don't have a
pod.

However, per-container generation was still generating a nearly
identical user namespace annotation to a pod. Example:

In Pod:
  io.podman.annotations.userns: auto:size=40
Not in Pod:
  io.podman.annotations.userns/awesomegreider: auto:size=2048

The second annotation seems like it should apply a user namespace
config to the generated Kubernetes pod. Instead, it's just adding
an annotation to the awesomegreider container, that says said
container has a user namespace, when it does not in fact have a
user namespace configured because it is now in a pod.

After this PR, both containers in and out of pods generate
identical annotations (the In Pod version, missing container
name) and as such should generate pods with appropriately
configured user namespaces. I also added some conflict detection
to refuse to generate if you try to generate YAML containing two
containers with conflicting user namespace configuration.

Fixes #25896

Signed-off-by: Matt Heon <mheon@redhat.com>
This commit is contained in:
Matt Heon 2025-04-22 13:09:14 -04:00
parent b849550997
commit 34748fbc4d
2 changed files with 32 additions and 1 deletions

View File

@ -765,7 +765,17 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container, getServic
if !podmanOnly && define.IsReservedAnnotation(k) {
continue
}
kubeAnnotations[fmt.Sprintf("%s/%s", k, removeUnderscores(ctr.Name()))] = v
// Certain annotations should be applied to the whole pod.
// For others, add container name as a suffix.
// For annotations such as this, error if already set.
if k == define.UserNsAnnotation {
if oldV, ok := kubeAnnotations[k]; ok && oldV != v {
return nil, fmt.Errorf("two or more containers have differing user namespace configuration, cannot place in same Kubernetes pod: %w", define.ErrInvalidArg)
}
kubeAnnotations[k] = v
} else {
kubeAnnotations[fmt.Sprintf("%s/%s", k, removeUnderscores(ctr.Name()))] = v
}
}
// Convert auto-update labels into kube annotations

View File

@ -1025,6 +1025,27 @@ var _ = Describe("Podman kube generate", func() {
Expect(kube).Should(ExitCleanly())
})
It("multiple containers with same user namespace configuration", func() {
name1 := "c1"
name2 := "c2"
_ = podmanTest.PodmanExitCleanly("run", "--userns", "auto:size=30", "-dt", "--name", name1, ALPINE, "top")
_ = podmanTest.PodmanExitCleanly("run", "--userns", "auto:size=30", "-dt", "--name", name2, ALPINE, "top")
gen := podmanTest.PodmanExitCleanly("kube", "generate", name1, name2)
Expect(gen.OutputToString()).To(ContainSubstring("io.podman.annotations.userns: auto:size=10"))
})
It("multiple containers with differing user namespace configuration", func() {
name1 := "c1"
name2 := "c2"
_ = podmanTest.PodmanExitCleanly("run", "--userns", "auto:size=30", "-dt", "--name", name1, ALPINE, "top")
_ = podmanTest.PodmanExitCleanly("run", "--userns", "auto:size=40", "-dt", "--name", name2, ALPINE, "top")
gen := podmanTest.Podman([]string{"kube", "generate", name1, name2})
gen.WaitWithDefaultTimeout()
Expect(gen).Should(ExitWithError(125, "two or more containers have differing user namespace configuration, cannot place in same Kubernetes pod: invalid argument"))
})
It("with containers in pods should fail", func() {
pod1 := podmanTest.Podman([]string{"run", "-dt", "--pod", "new:pod1", "--name", "top1", CITEST_IMAGE, "top"})
pod1.WaitWithDefaultTimeout()