Repository navigation
Preview node drains with a read-only, honest drain plan #1584
Description
Problem
Draining a node cordons it and evicts eligible pods. Radar currently shows one generic confirmation and immediately mutates the cluster. It does not show which pods it expects to evict or skip, why, or that it sends deleteEmptyDirData: true without an explicit acknowledgement.
Operators need a read-only estimate before committing a destructive operation. It must be honest: pods, PDB budgets, and permissions can change between the preview and the real drain.
Goal
Replace the generic confirmation with a server-backed drain plan. Opening it must not cordon, evict, or otherwise mutate the cluster. The operator reviews the expected effects and explicit options, then starts the existing drain flow, which re-lists and evaluates live state again.
Scope
-
Extract the current drain eligibility decisions into a pure, reusable classifier in
pkg/k8score.- Return a per-pod outcome and operator-facing reason.
- Cover terminal pods, mirror/static pods, DaemonSet pods, unmanaged pods, and pods that use
emptyDir. - Treat a pod as managed only when it has a controller owner reference.
-
Add a read-only drain-plan endpoint beside the existing drain endpoint.
- Use the requesting user’s cluster client and RBAC identity.
- Accept the same relevant options: force,
deleteEmptyDirData, and grace period. - Return evaluated options, generation time, summary counts, and per-pod
evict,skip, ormay-blockoutcomes with reasons. - A matching PDB with currently exhausted
disruptionsAllowedis useful evidence, but never a guarantee: the Eviction API and live state are authoritative.
-
Replace the generic Drain Node confirmation with a focused plan dialog.
- Fetch and display the plan before enabling the destructive action.
- Explicitly label the result as an estimate that is re-evaluated on execution.
- Start with
deleteEmptyDirDatadisabled. Require an explicit acknowledgement before affected pods can be evicted. - Keep force-unmanaged-pods explicit and explain it.
-
Make post-drain results legible: actual evictions, skips, and individual failures.
Important constraints
- Previewing must make no cluster mutation.
- Do not represent missing or uncomputed information as zero.
- Do not claim that a preview proves a drain will succeed.
- This is not a generic preflight framework and does not change the MCP drain tool.
Starting points
pkg/k8score/node_ops.gointernal/server/node_handlers.goweb/src/api/client.tspackages/k8s-ui/src/components/shared/ResourceActionsBar.tsx
There are no focused drain tests today. Please add unit coverage for the classifier and preview handler, plus frontend coverage that viewing the plan does not mutate the cluster and that emptyDir acknowledgement is required.
Acceptance criteria
- Opening Drain Node shows a read-only plan; neither cordon nor eviction happens until final confirmation.
- The plan makes expected eviction, skip, and currently PDB-constrained outcomes legible with reasons.
- The UI calls the plan an estimate and execution re-evaluates live state.
-
emptyDirdata is never silently included; the operator explicitly opts in. - Managed-owner detection requires a controller owner reference.
- Execution reports actual evictions and individual skips/failures.
Activity
alexeymoskalev-devops commentedon Sep 8, 2026
Hi @nadaverell, I'd like to take this one.
I went through the current code before writing this, so here is how I plan to approach it and a few points I'd like to confirm before opening a PR.
Plan, following the scope in the issue
pkg/k8score. Extract the decisions fromshouldSkipPodinto a pure function that returns a per-pod outcome (evict/skip/may-block) plus an operator-facing reason. Cases: terminal pods, mirror pods, DaemonSet pods, unmanaged pods (only a controller owner reference counts, viametav1.GetControllerOf, matching the rest of the codebase; todayhasManagedOwneraccepts any owner reference), pods usingemptyDir, and pods matched by a PDB whosestatus.disruptionsAllowedis 0 →may-block.DrainNodegets rewritten on top of the classifier so preview and execution share one code path. Signature stays the same, so the MCPmanage_nodetool is untouched.estimate: true. If listing PDBs is forbidden, the response says PDBs were not evaluated instead of reporting zero.ResourceActionsBar: fetch the plan before enabling Drain, label it as an estimate that is re-evaluated on execution, start withdeleteEmptyDirDataoff and require an explicit acknowledgement, keep force-unmanaged explicit with an explanation.DrainResultcarry skipped pods with reasons and per-pod failures (additive fields), and show evicted / skipped / failed in the UI after execution.Tests: table-driven unit tests for the classifier; a handler test on a fake clientset asserting the plan endpoint issues no patch/evict actions; frontend tests that opening the plan does not call drain and that pods with
emptyDirare excluded without the acknowledgement. Smoke on a kind cluster with a PDB at its budget, anemptyDirpod, a bare pod and a DaemonSet.Questions
POST /nodes/{name}/drain-plantaking the same JSON body as drain, orGETwith query params?may-block, I intend to report only a matching PDB withdisruptionsAllowed == 0as evidence, never as a guarantee, as the issue says. Fine to leave percentage/multi-PDB reasoning to the Eviction API at execution time?If this direction works for you, please assign it to me and I'll get the first PR up within a few days.
feat(nodes): drain plan — classifier, read-only endpoint and plan dia…