Skip to content

fix: clean up temp dirs and close fd leaks in Helm, Kustomize, Cuelang - #1551

Open
kaizeenn wants to merge 1 commit into
kapicorp:masterfrom
kaizeenn:fix/1509-temp-dir-fd-leaks
Open

fix: clean up temp dirs and close fd leaks in Helm, Kustomize, Cuelang#1551
kaizeenn wants to merge 1 commit into
kapicorp:masterfrom
kaizeenn:fix/1509-temp-dir-fd-leaks

Conversation

@kaizeenn

Copy link
Copy Markdown

Summary

Fixes #1509.

Three input compilers created temp directories with tempfile.mkdtemp() and never cleaned them up. Two tempfile.mkstemp() calls discarded the returned file descriptor (_) without closing it. On large or long-running compilation jobs this causes disk-space exhaustion and file-descriptor leaks.

Changes

kapitan/inputs/helm.py

  • compile_file: replace mkdtemp() with tempfile.TemporaryDirectory() context manager — rendered-chart dir is now always deleted on exit, even if an exception is raised.
  • render_chart: close the mkstemp() fd immediately with os.close(fd), then os.unlink() the temp file after its contents are read.
  • write_helm_values_file: close the mkstemp() fd immediately with os.close(fd) before opening the file for writing.

kapitan/inputs/kustomize.py

  • compile_file: replace two separate mkdtemp() calls with a single with tempfile.TemporaryDirectory() as temp_dir, tempfile.TemporaryDirectory() as output_dir: block; consolidate the previously split try/except blocks into one, re-raising KustomizeTemplateError directly so it is not double-wrapped.

kapitan/inputs/cuelang.py

  • compile_file: replace mkdtemp() with tempfile.TemporaryDirectory() context manager.

Testing

All pre-existing test failures (helm/kustomize/cuelang suites require helm/kustomize/cue binaries not present in CI) are identical before and after this change — no regressions introduced.

…omize, Cuelang

Temp directories created with tempfile.mkdtemp() were never removed, and
file descriptors returned by tempfile.mkstemp() were discarded without
being closed. On large compilation runs this caused disk-space and file-
descriptor exhaustion.

Changes:
- helm.py compile_file: replace mkdtemp() with TemporaryDirectory()
  context manager so the rendered-chart temp dir is always deleted.
- helm.py render_chart: close the mkstemp() fd immediately with
  os.close(fd), then unlink the temp file after reading it.
- helm.py write_helm_values_file: close the mkstemp() fd immediately
  with os.close(fd) before opening the file for writing.
- kustomize.py compile_file: replace two mkdtemp() calls with a single
  nested TemporaryDirectory() context manager; consolidate the two
  try/except blocks into one.
- cuelang.py compile_file: replace mkdtemp() with TemporaryDirectory()
  context manager.

Fixes kapicorp#1509

Signed-off-by: kaizeenn <khairil0153@gmail.com>

@Moep90 Moep90 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mkdtempTemporaryDirectory() conversions and both fd closes look correct, and the kustomize except KustomizeTemplateError: raise ahead of the generic handler nicely avoids the double-wrap. One inline nit on exception-safety below; non-blocking.

Two related leaks I found while reviewing, both pre-existing and out of scope here, were opened as separate PRs rather than expanding this one:

  • #1555 write_helm_values_file()'s temp file is never unlinked by either caller. The fd half is covered here; the file lifecycle isn't. Complementary to this PR, it does touch compile_file, so expect a small conflict with whichever of us merges second.
  • #1554 unrelated to #1509: cuelang.py raises KustomizeTemplateError (copy-paste) when CuelangTemplateError already exists in kapitan/errors.py.

Nice cleanup overall.

Comment thread kapitan/inputs/helm.py
f.seek(0)
return (f.read(), error_message)
content = f.read()
os.unlink(helm_output)

@Moep90 Moep90 Jun 15, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

os.unlink here isn't exception-safe if helm_cli or f.read() above raises; this line is skipped and the temp file leaks (the same bug class this PR targets). Wrap in try/finally, or let a context manager delete on exit:

with tempfile.NamedTemporaryFile(suffix=".helm_output.yml", mode="w+") as f:
    error_message = helm_cli(helm_path, args, stdout=f)
    f.seek(0)
    return (f.read(), error_message)

Low real-world risk since helm_cli returns the error rather than raising non-blocking.

@ramaro

ramaro commented Jun 15, 2026

Copy link
Copy Markdown
Member

@kaizeenn thanks for sending this in. However this approach seems to repeat the same formula in the mentioned input types. Perhaps we can abstract this in the base class or have common generic functions to avoid duplication?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Pull requests that update Python code size/m

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug] Temp directory and file descriptor leaks in Helm, Kustomize, Cuelang input compilers

3 participants