Skip to content

Commit

Permalink
Add ulimit annotation to kube gen & play
Browse files Browse the repository at this point in the history
Add a podman ulimit annotation to kube generate and play.
If a container has a container with ulimits set, kube gen
will add those as an annotation to the generated yaml.
If kube play encounters the ulimit annotation, it will set
ulimits for the container being played.

Signed-off-by: Urvashi Mohnani <[email protected]>
  • Loading branch information
umohnani8 committed Feb 13, 2023
1 parent 86da741 commit 35d16ea
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 1 deletion.
4 changes: 4 additions & 0 deletions libpod/define/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ const (
// of the init container.
InitContainerType = "io.podman.annotations.init.container.type"

// UlimitAnnotation is used by kube play when playing a kube yaml to specify the ulimits
// of the container
UlimitAnnotation = "io.podman.annotations.ulimit"

// MaxKubeAnnotation is the max length of annotations allowed by Kubernetes.
MaxKubeAnnotation = 63
)
Expand Down
18 changes: 18 additions & 0 deletions libpod/kube.go
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,24 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container) (*v1.Pod,
}
}

if ctr.config.Spec.Process != nil {
var ulimitArr []string
defaultUlimits := util.DefaultContainerConfig().Ulimits()
for _, ulimit := range ctr.config.Spec.Process.Rlimits {
finalUlimit := strings.ToLower(strings.ReplaceAll(ulimit.Type, "RLIMIT_", "")) + "=" + strconv.Itoa(int(ulimit.Soft)) + ":" + strconv.Itoa(int(ulimit.Hard))
// compare ulimit with default list so we don't add it twice
if cutil.StringInSlice(finalUlimit, defaultUlimits) {
continue
}

ulimitArr = append(ulimitArr, finalUlimit)
}

if len(ulimitArr) > 0 {
kubeAnnotations[define.UlimitAnnotation] = strings.Join(ulimitArr, ",")
}
}

if !ctr.HostNetwork() {
hostNetwork = false
}
Expand Down
12 changes: 12 additions & 0 deletions pkg/specgen/generate/kube/kube.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,18 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener
s.ResourceLimits.Memory.Reservation = &memoryRes
}

ulimitVal, ok := opts.Annotations[define.UlimitAnnotation]
if ok {
ulimits := strings.Split(ulimitVal, ",")
for _, ul := range ulimits {
parsed, err := units.ParseUlimit(ul)
if err != nil {
return nil, err
}
s.Rlimits = append(s.Rlimits, spec.POSIXRlimit{Type: parsed.Name, Soft: uint64(parsed.Soft), Hard: uint64(parsed.Hard)})
}
}

// TODO: We don't understand why specgen does not take of this, but
// integration tests clearly pointed out that it was required.
imageData, err := opts.Image.Inspect(ctx, nil)
Expand Down
37 changes: 36 additions & 1 deletion test/e2e/generate_kube_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ var _ = Describe("Podman kube generate", func() {
Expect(pod.Spec.Containers[0].SecurityContext).To(BeNil())
Expect(pod.Spec.Containers[0].Env).To(BeNil())
Expect(pod).To(HaveField("Name", "top-pod"))
Expect(pod.Annotations).To(HaveLen(0))

numContainers := 0
for range pod.Spec.Containers {
Expand Down Expand Up @@ -1330,4 +1329,40 @@ USER test1`

Expect(pod.Spec.Volumes[0].Secret).To(BeNil())
})

It("podman generate & play kube with --ulimit set", func() {
ctrName := "ulimit-ctr"
ctrNameInKubePod := ctrName + "-pod-" + ctrName
session1 := podmanTest.Podman([]string{"run", "-d", "--name", ctrName, "--ulimit", "nofile=1231:3123", ALPINE, "sleep", "1000"})
session1.WaitWithDefaultTimeout()
Expect(session1).Should(Exit(0))

outputFile := filepath.Join(podmanTest.RunRoot, "pod.yaml")
kube := podmanTest.Podman([]string{"kube", "generate", ctrName, "-f", outputFile})
kube.WaitWithDefaultTimeout()
Expect(kube).Should(Exit(0))

b, err := os.ReadFile(outputFile)
Expect(err).ShouldNot(HaveOccurred())
pod := new(v1.Pod)
err = yaml.Unmarshal(b, pod)
Expect(err).ToNot(HaveOccurred())
Expect(pod.Annotations).To(HaveKey(define.UlimitAnnotation))
Expect(pod.Annotations[define.UlimitAnnotation]).To(ContainSubstring("nofile=1231:3123"))

rm := podmanTest.Podman([]string{"pod", "rm", "-t", "0", "-f", ctrName})
rm.WaitWithDefaultTimeout()
Expect(rm).Should(Exit(0))

play := podmanTest.Podman([]string{"kube", "play", outputFile})
play.WaitWithDefaultTimeout()
Expect(play).Should(Exit(0))

inspect := podmanTest.Podman([]string{"inspect", ctrNameInKubePod})
inspect.WaitWithDefaultTimeout()
Expect(inspect).Should(Exit(0))
Expect(inspect.OutputToString()).To(ContainSubstring("RLIMIT_NOFILE"))
Expect(inspect.OutputToString()).To(ContainSubstring("1231"))
Expect(inspect.OutputToString()).To(ContainSubstring("3123"))
})
})

0 comments on commit 35d16ea

Please sign in to comment.