Skip to content

[CASCL-1386] (8/11) Add node drain primitives and evict ASG nodes#3175

Merged
L3n41c merged 3 commits into
mainfrom
lenaic/CASCL-1386-evict-08-drain-and-asg
Jul 3, 2026
Merged

[CASCL-1386] (8/11) Add node drain primitives and evict ASG nodes#3175
L3n41c merged 3 commits into
mainfrom
lenaic/CASCL-1386-evict-08-drain-and-asg

Conversation

@L3n41c

@L3n41c L3n41c commented Jun 18, 2026

Copy link
Copy Markdown
Member

What does this PR do?

Introduces the shared node-drain primitives — node cordoning (cordonNodes), pod eviction/draining (drainNode) and the pod-eligibility predicates (shouldSkipEviction …) — together with their first consumer, ASG eviction (cordon, drain, terminate the instances, lock the ASG to 0).

Motivation

PR #3026 is too large to review as a single change. This is part 8 of 11 of a stack that splits it into small, individually-reviewable pieces that each build and pass tests on their own. See #3026 for the full feature context and end-to-end QA.

Additional Notes

Stacked PR — the base branch is lenaic/CASCL-1386-evict-07-eks-mng, not main, so the diff shows only this step's change. The drain primitives are bundled with the ASG evictor on purpose: golangci-lint's unused linter rejects an unexported helper that has no caller in the same commit, so the primitives land in the same PR as the first evictor that calls them. Parts 9–10 reuse them. The code is taken verbatim from #3026 (rebased onto main); there are no logic changes versus #3026.

Minimum Agent Versions

N/A — kubectl-datadog plugin only.

Describe your test plan

go test ./cmd/kubectl-datadog/autoscaling/cluster/... passes at this commit. Full end-to-end QA is tracked on #3026.

Checklist

@codecov-commenter

codecov-commenter commented Jun 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.69697% with 17 lines in your changes missing coverage. Please review.
✅ Project coverage is 44.36%. Comparing base (6c79f69) to head (bc40e36).

Files with missing lines Patch % Lines
...tl-datadog/autoscaling/cluster/evict/evict_pods.go 78.94% 11 Missing and 5 partials ⚠️
...ubectl-datadog/autoscaling/cluster/evict/cordon.go 96.42% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@                          Coverage Diff                           @@
##           lenaic/CASCL-1386-evict-07-eks-mng    #3175      +/-   ##
======================================================================
+ Coverage                               44.12%   44.36%   +0.24%     
======================================================================
  Files                                     389      391       +2     
  Lines                                   31132    31296     +164     
======================================================================
+ Hits                                    13737    13886     +149     
- Misses                                  16501    16511      +10     
- Partials                                  894      899       +5     
Flag Coverage Δ
unittests 44.36% <89.69%> (+0.24%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...d/kubectl-datadog/autoscaling/cluster/evict/asg.go 100.00% <100.00%> (+100.00%) ⬆️
...ubectl-datadog/autoscaling/cluster/evict/cordon.go 96.42% <96.42%> (ø)
...tl-datadog/autoscaling/cluster/evict/evict_pods.go 78.94% <78.94%> (ø)

Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6c79f69...bc40e36. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@datadog-datadog-prod-us1-2

datadog-datadog-prod-us1-2 Bot commented Jun 18, 2026

Copy link
Copy Markdown

Code Coverage

🎯 Code Coverage (details)
Patch Coverage: 100.00%
Overall Coverage: 45.34%

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 3757a85 | Docs | Datadog PR Page | Give us feedback!

@L3n41c
L3n41c force-pushed the lenaic/CASCL-1386-evict-08-drain-and-asg branch from 22c07f1 to 5bad6e2 Compare June 19, 2026 14:21
@L3n41c
L3n41c force-pushed the lenaic/CASCL-1386-evict-07-eks-mng branch from c0c8b6a to 9250b71 Compare June 19, 2026 14:21
@L3n41c
L3n41c force-pushed the lenaic/CASCL-1386-evict-08-drain-and-asg branch from 5bad6e2 to e2962ee Compare June 19, 2026 14:45
@L3n41c
L3n41c force-pushed the lenaic/CASCL-1386-evict-07-eks-mng branch from 9250b71 to f9c10d1 Compare June 22, 2026 13:24
@L3n41c
L3n41c force-pushed the lenaic/CASCL-1386-evict-08-drain-and-asg branch from e2962ee to 0b04574 Compare June 22, 2026 13:25
@L3n41c
L3n41c force-pushed the lenaic/CASCL-1386-evict-07-eks-mng branch from f9c10d1 to 8e43ad1 Compare June 23, 2026 08:49
@L3n41c
L3n41c force-pushed the lenaic/CASCL-1386-evict-08-drain-and-asg branch 2 times, most recently from 1e9f157 to ef93860 Compare June 25, 2026 08:18
@L3n41c
L3n41c force-pushed the lenaic/CASCL-1386-evict-07-eks-mng branch from 8e43ad1 to 3718447 Compare June 25, 2026 08:18
@L3n41c
L3n41c force-pushed the lenaic/CASCL-1386-evict-08-drain-and-asg branch from ef93860 to bc40e36 Compare June 26, 2026 12:16
@L3n41c
L3n41c force-pushed the lenaic/CASCL-1386-evict-07-eks-mng branch 2 times, most recently from 6c79f69 to 0816a9f Compare June 26, 2026 14:45
@L3n41c
L3n41c force-pushed the lenaic/CASCL-1386-evict-08-drain-and-asg branch 2 times, most recently from 1b6d08b to 9b63eda Compare June 29, 2026 15:41
@L3n41c
L3n41c force-pushed the lenaic/CASCL-1386-evict-07-eks-mng branch from f91f53d to 7322549 Compare June 29, 2026 15:41
@L3n41c
L3n41c marked this pull request as ready for review June 29, 2026 15:58
@L3n41c
L3n41c requested review from a team as code owners June 29, 2026 15:58

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9b63edab8e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread cmd/kubectl-datadog/autoscaling/cluster/evict/evict_pods.go
Comment thread cmd/kubectl-datadog/autoscaling/cluster/evict/asg.go
// return values); a node that fails to cordon is recorded in errs and left out
// of cordoned so the caller never drains a node that can still receive pods.
func cordonNodes(ctx context.Context, clientset kubernetes.Interface, nodes []string, dryRun bool) (cordoned []*corev1.Node, errs []error) {
for _, nodeName := range nodes {

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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The benefit of parallelizing the cordoning in term of wall clock time would be minimal because cordoning the nodes is blazing fast compared to draining their pods.
And I’d prefer to keep nodes draining sequential in this first iteration to:

  • minimize the disruption caused to the customer’s workload,
  • minimize the stress caused to the API server.
    Thanks to the PDB protection, it should theoretically be possible to parallelize the drain of all the nodes, but I’m a bit afraid of the load it might generate on the API server.

Using errgroup would also change the way errors are managed.
Current behavior is best-effort: if cordoning a single node fails, we register that error to surface it later, but we keep on cordoning the remaining nodes.
errgroup behavior is more fail-early: it makes all the goroutines abort as soon as one of them returns an error.
In order to avoid too many back and forth with the user, I think it’s better to clean up as much nodes as possible before asking the user to manually fix something and relaunch the script.

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.

errgroup behavior is more fail-early

You can code worker to not return error but, yeah, I agree its better start simple and then optimize the bottlenecks.

@L3n41c
L3n41c force-pushed the lenaic/CASCL-1386-evict-07-eks-mng branch from 3d6b702 to 409d632 Compare July 1, 2026 16:48
@L3n41c
L3n41c force-pushed the lenaic/CASCL-1386-evict-08-drain-and-asg branch from 9b63eda to 7dc54d8 Compare July 1, 2026 17:09
@L3n41c
L3n41c force-pushed the lenaic/CASCL-1386-evict-07-eks-mng branch from 409d632 to 5884694 Compare July 1, 2026 22:58
@L3n41c
L3n41c force-pushed the lenaic/CASCL-1386-evict-08-drain-and-asg branch from 7dc54d8 to 21505f9 Compare July 1, 2026 22:58
L3n41c added 2 commits July 2, 2026 11:38
Introduce the reusable node-cordon and pod-eviction/drain primitives that the
per-manager evictors (EKS managed node groups, ASG, Karpenter, standalone)
build on:

- cordonNodes/cordonNode: idempotent, conflict-retrying cordon that treats an
  already-gone node as a silent skip and returns the cordoned Node objects.
- drainNode: evicts every evictable pod (skipping mirror, DaemonSet, completed
  and terminating pods), then waits for the node to empty.
- evictPodWithRetry: PDB-aware eviction that retries on 429 and treats 404 as
  success.
- listPodsOnNode, waitForNodeEmpty and the pod-classification predicates
  (podOccupiesNode/shouldSkipEviction/isMirrorPod/isDaemonSetPod/isCompleted).

These primitives have no production caller yet; the first (evictEKSManagedNode-
Group) lands in the next PR in the stack. A temporary blank-identifier
reference keeps golangci-lint's `unused` quiet until then (the linter runs with
tests = false, so the unit tests do not count as use) and is removed by that PR.
Part of a stack splitting #3026 (too large to review in one piece) into
small pieces that each build and pass tests on their own. The command is
fully functional only once the whole stack lands.
@L3n41c
L3n41c force-pushed the lenaic/CASCL-1386-evict-07-eks-mng branch from 5884694 to eec5e58 Compare July 2, 2026 09:43
@L3n41c
L3n41c force-pushed the lenaic/CASCL-1386-evict-08-drain-and-asg branch from 21505f9 to b346c58 Compare July 2, 2026 09:43
Part of a stack splitting #3026 (too large to review in one piece) into
small pieces that each build and pass tests on their own. The command is
fully functional only once the whole stack lands.
@L3n41c
L3n41c force-pushed the lenaic/CASCL-1386-evict-08-drain-and-asg branch from b346c58 to 3757a85 Compare July 2, 2026 12:53
Base automatically changed from lenaic/CASCL-1386-evict-07-eks-mng to main July 3, 2026 09:27
@L3n41c
L3n41c merged commit 110b9f5 into main Jul 3, 2026
36 checks passed
@L3n41c
L3n41c deleted the lenaic/CASCL-1386-evict-08-drain-and-asg branch July 3, 2026 09:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants