Skip to content

[CASCL-1304] Fix Fargate profile name in dd-cluster-info ConfigMap#3000

Merged
L3n41c merged 3 commits into
mainfrom
lenaic/CASCL-1304-fix-fargate-profile-in-cluster-info
May 13, 2026
Merged

[CASCL-1304] Fix Fargate profile name in dd-cluster-info ConfigMap#3000
L3n41c merged 3 commits into
mainfrom
lenaic/CASCL-1304-fix-fargate-profile-in-cluster-info

Conversation

@L3n41c

@L3n41c L3n41c commented May 11, 2026

Copy link
Copy Markdown
Member

What does this PR do?

Fix the empty Fargate profile-name bucket key in the dd-cluster-info
ConfigMap written at the end of kubectl datadog autoscaling cluster install.

Before the fix, on a real EKS cluster the snapshot looked like:

nodeManagement:
    fargate:
        "":
            - fargate-ip-10-11-232-98.eu-west-3.compute.internal
            - fargate-ip-10-11-234-113.eu-west-3.compute.internal

After the fix:

nodeManagement:
    fargate:
        dd-karpenter-lenaic-karpenter-test:
            - fargate-ip-10-11-233-199.eu-west-3.compute.internal
            - fargate-ip-10-11-233-23.eu-west-3.compute.internal
            - fargate-ip-10-11-234-235.eu-west-3.compute.internal

Motivation

Root cause: classifyNodeByLabel (introduced in #2945) read the Fargate
profile name from a label on the Node:

return NodeManagerFargate, node.Labels["eks.amazonaws.com/fargate-profile"], true

EKS does not put that label on the Node — it stamps it on the Pod
scheduled on the Fargate node. Verified on a live cluster: the Fargate
Node only carries eks.amazonaws.com/compute-type=fargate and topology
labels; the hosted pod is the one carrying eks.amazonaws.com/fargate-profile.
So the read always returned an empty string, and the ConfigMap collapsed
every Fargate node into the fargate: { "": [...] } bucket — making the
profile information unusable for the follow-up migration tooling.

Tracked in CASCL-1304.

Additional Notes

  • The new fargateProfilesByNode helper lists Pods cluster-wide with a
    server-side label-existence selector
    (LabelSelector: "eks.amazonaws.com/fargate-profile") and builds a
    nodeName → profileName index. On non-Fargate clusters the filtered
    list returns empty cheaply; the install path already does cluster-wide
    Nodes.List and Deployments.List so the incremental pods.list
    perm is small.
  • A Fargate node with no Pod yet scheduled still falls into the
    empty-key bucket — acceptable race window for a one-shot informational
    snapshot.
  • No new AWS permission required; the fix is pure Kubernetes API.

Minimum Agent Versions

  • Agent: N/A (kubectl plugin only — no Agent/Cluster Agent code path is touched)
  • Cluster Agent: N/A

Describe your test plan

  • Unit tests in cmd/kubectl-datadog/autoscaling/cluster/common/clusterinfo/classify_test.go:
    • TestClassify_AllBucketsByLabel updated to put the profile label on
      a Pod scheduled on the Fargate node; preserves the empty-key fallback
      coverage via the name-fallback case (no pod yet scheduled).
    • TestClassify_FargateMultipleProfiles (new) verifies two distinct
      Fargate profiles produce two distinct bucket keys.
    • Run with:
      go test ./cmd/kubectl-datadog/autoscaling/cluster/common/clusterinfo/...
  • End-to-end on a real EKS cluster (verified on lenaic-karpenter-test):
    make kubectl-datadog
    kubectl datadog autoscaling cluster install --cluster-name <cluster>
    kubectl -n dd-karpenter get cm/dd-cluster-info -o yaml
    Cross-check the fargate bucket keys against
    aws eks list-fargate-profiles --cluster-name <cluster>.

Checklist

  • PR has at least one valid label: bug, enhancement, refactoring, documentation, tooling, and/or dependencies
  • PR has a milestone or the qa/skip-qa label
  • All commits are signed

🤖 Generated with Claude Code

The dd-cluster-info ConfigMap was writing an empty string as the
Fargate profile-name bucket key, because `classifyNodeByLabel` read
`eks.amazonaws.com/fargate-profile` from the Node. EKS stamps that
label on the Pod scheduled on the Fargate node, not on the Node
itself, so the read always returned "".

Resolve the profile name by listing Pods filtered server-side with
`LabelSelector: "eks.amazonaws.com/fargate-profile"`, building a
nodeName→profileName index, and threading it through the classifier.
A Fargate node with no Pod yet scheduled keeps falling into the
empty-key bucket — acceptable for a one-shot informational snapshot.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@L3n41c

L3n41c commented May 11, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🎉

ℹ️ 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".

@codecov-commenter

codecov-commenter commented May 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 40.90%. Comparing base (2c675b3) to head (9c49adc).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #3000      +/-   ##
==========================================
+ Coverage   40.86%   40.90%   +0.04%     
==========================================
  Files         334      334              
  Lines       28307    28327      +20     
==========================================
+ Hits        11568    11588      +20     
  Misses      15960    15960              
  Partials      779      779              
Flag Coverage Δ
unittests 40.90% <100.00%> (+0.04%) ⬆️

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

Files with missing lines Coverage Δ
...autoscaling/cluster/common/clusterinfo/classify.go 88.52% <100.00%> (+1.40%) ⬆️

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2c675b3...9c49adc. 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

This comment has been minimized.

…esByNode

The patch coverage gate failed at 72.72% (threshold 80%) because three new
branches in classify.go were untested:
- Classify error-return when fargateProfilesByNode fails.
- The empty-NodeName skip path in fargateProfilesByNode.
- The List error wrap path in fargateProfilesByNode.

Adds two tests that close those branches via fake-clientset reactors and a
pending pod fixture, mirroring the existing API-list-error pattern in
guess/karpenter_test.go. fargateProfilesByNode now reaches 100% statement
coverage and the package totals 93.9%.
@L3n41c
L3n41c marked this pull request as ready for review May 11, 2026 15:35
@L3n41c
L3n41c requested review from a team as code owners May 11, 2026 15:35
@L3n41c L3n41c changed the title [CASCL-1304] Fix Fargate profile name in dd-cluster-info ConfigMap [CASCL-1304] Fix Fargate profile name in dd-cluster-info ConfigMap May 12, 2026
…-fargate-profile-in-cluster-info

# Conflicts:
#	cmd/kubectl-datadog/autoscaling/cluster/common/clusterinfo/classify.go
#	cmd/kubectl-datadog/autoscaling/cluster/common/clusterinfo/classify_test.go
@L3n41c
L3n41c merged commit b9f5936 into main May 13, 2026
30 of 39 checks passed
@L3n41c
L3n41c deleted the lenaic/CASCL-1304-fix-fargate-profile-in-cluster-info branch May 13, 2026 21:13
L3n41c added a commit that referenced this pull request May 13, 2026
Continue the redistribution of `guess/` started by PRs #2980 and #3000:
move every helper that operates on an EKS cluster object or the EKS API
into a dedicated `common/eks/` package. After this commit, `common/eks/`
contains:
  - authmode.go (was guess/clusterauthmode.go)
  - podidentityagent.go (was guess/ekspodidentityagent.go)
  - oidcprovider.go (was guess/oidcprovider.go)
  - privatesubnets.go (was guess/privatesubnets.go)

Import alias `commoneks` is used to avoid colliding with the existing
`github.com/aws/aws-sdk-go-v2/service/eks` (aliased `eks`).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
L3n41c added a commit that referenced this pull request May 13, 2026
…rn (#3012)

* kubectl-datadog: extract EKS helpers to common/eks/

Continue the redistribution of `guess/` started by PRs #2980 and #3000:
move every helper that operates on an EKS cluster object or the EKS API
into a dedicated `common/eks/` package. After this commit, `common/eks/`
contains:
  - authmode.go (was guess/clusterauthmode.go)
  - podidentityagent.go (was guess/ekspodidentityagent.go)
  - oidcprovider.go (was guess/oidcprovider.go)
  - privatesubnets.go (was guess/privatesubnets.go)

Import alias `commoneks` is used to avoid colliding with the existing
`github.com/aws/aws-sdk-go-v2/service/eks` (aliased `eks`).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* kubectl-datadog: consolidate aws-auth into common/awsauth/

`common/aws/aws-auth.go` was misnamed: it manipulates a Kubernetes
ConfigMap (`kube-system/aws-auth`), not an AWS-SDK resource. Together
with `guess/aws-auth.go` (read-only presence check), it belongs in a
dedicated `common/awsauth/` package: both files operate on the same
ConfigMap.

Function names lose the now-redundant `AwsAuth` prefix:
  - `IsAwsAuthConfigMapPresent` -> `IsConfigMapPresent`
  - `EnsureAwsAuthRole`         -> `EnsureRole`
  - `RemoveAwsAuthRole`         -> `RemoveRole`

`common/aws/` now contains only cloudformation.go (pure AWS-SDK).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* kubectl-datadog: fold clustername into common/clients/

The only caller of `guess.GetClusterNameFromKubeconfig` is the wrapper
`clients.GetClusterNameFromKubeconfig` in `common/clients/clients.go`.
Move the helper next to its caller as an unexported function
`clusterNameFromKubeconfig`. The public API of `common/clients/` is
unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* kubectl-datadog: carve out karpenter package

Consolidate everything Karpenter-shaped into `common/karpenter/`,
alongside the existing detection helper:

- Intermediate model: NodePoolsSet, EC2NodeClass, NodePool,
  MetadataOptions, BlockDeviceMapping (from guess/nodepoolsset.go)
- Producers from EKS node groups: GetNodeGroupsProperties (from
  guess/nodegroupproperties.go -> fromnodegroups.go)
- Producers from running k8s Nodes: GetNodesProperties (from
  guess/nodesproperties.go -> fromnodes.go)
- CR builders: CreateOrUpdateEC2NodeClass, CreateOrUpdateNodePool
  (from cluster/k8s/{ec2nodeclass,nodepool}.go)

`cluster/k8s/` is gone (it was misnamed: those files build Karpenter
CRDs, they aren't generic k8s primitives). `common/k8s/` keeps its
narrow scope: generic object CRUD + deployment-finder.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* kubectl-datadog: awsauth: extract ConfigMap name/namespace constants

`kube-system` and `aws-auth` each appeared 5 times across the three
functions. Promote them to package-level constants so the package's
single-ConfigMap scope is explicit at a glance.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
tbavelier pushed a commit that referenced this pull request May 20, 2026
…3000)

* [CASCL-1304] Fix Fargate profile name in dd-cluster-info ConfigMap

The dd-cluster-info ConfigMap was writing an empty string as the
Fargate profile-name bucket key, because `classifyNodeByLabel` read
`eks.amazonaws.com/fargate-profile` from the Node. EKS stamps that
label on the Pod scheduled on the Fargate node, not on the Node
itself, so the read always returned "".

Resolve the profile name by listing Pods filtered server-side with
`LabelSelector: "eks.amazonaws.com/fargate-profile"`, building a
nodeName→profileName index, and threading it through the classifier.
A Fargate node with no Pod yet scheduled keeps falling into the
empty-key bucket — acceptable for a one-shot informational snapshot.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* [CASCL-1304] Cover error and empty-NodeName branches of fargateProfilesByNode

The patch coverage gate failed at 72.72% (threshold 80%) because three new
branches in classify.go were untested:
- Classify error-return when fargateProfilesByNode fails.
- The empty-NodeName skip path in fargateProfilesByNode.
- The List error wrap path in fargateProfilesByNode.

Adds two tests that close those branches via fake-clientset reactors and a
pending pod fixture, mirroring the existing API-list-error pattern in
guess/karpenter_test.go. fargateProfilesByNode now reaches 100% statement
coverage and the package totals 93.9%.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
tbavelier pushed a commit that referenced this pull request May 20, 2026
…rn (#3012)

* kubectl-datadog: extract EKS helpers to common/eks/

Continue the redistribution of `guess/` started by PRs #2980 and #3000:
move every helper that operates on an EKS cluster object or the EKS API
into a dedicated `common/eks/` package. After this commit, `common/eks/`
contains:
  - authmode.go (was guess/clusterauthmode.go)
  - podidentityagent.go (was guess/ekspodidentityagent.go)
  - oidcprovider.go (was guess/oidcprovider.go)
  - privatesubnets.go (was guess/privatesubnets.go)

Import alias `commoneks` is used to avoid colliding with the existing
`github.com/aws/aws-sdk-go-v2/service/eks` (aliased `eks`).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* kubectl-datadog: consolidate aws-auth into common/awsauth/

`common/aws/aws-auth.go` was misnamed: it manipulates a Kubernetes
ConfigMap (`kube-system/aws-auth`), not an AWS-SDK resource. Together
with `guess/aws-auth.go` (read-only presence check), it belongs in a
dedicated `common/awsauth/` package: both files operate on the same
ConfigMap.

Function names lose the now-redundant `AwsAuth` prefix:
  - `IsAwsAuthConfigMapPresent` -> `IsConfigMapPresent`
  - `EnsureAwsAuthRole`         -> `EnsureRole`
  - `RemoveAwsAuthRole`         -> `RemoveRole`

`common/aws/` now contains only cloudformation.go (pure AWS-SDK).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* kubectl-datadog: fold clustername into common/clients/

The only caller of `guess.GetClusterNameFromKubeconfig` is the wrapper
`clients.GetClusterNameFromKubeconfig` in `common/clients/clients.go`.
Move the helper next to its caller as an unexported function
`clusterNameFromKubeconfig`. The public API of `common/clients/` is
unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* kubectl-datadog: carve out karpenter package

Consolidate everything Karpenter-shaped into `common/karpenter/`,
alongside the existing detection helper:

- Intermediate model: NodePoolsSet, EC2NodeClass, NodePool,
  MetadataOptions, BlockDeviceMapping (from guess/nodepoolsset.go)
- Producers from EKS node groups: GetNodeGroupsProperties (from
  guess/nodegroupproperties.go -> fromnodegroups.go)
- Producers from running k8s Nodes: GetNodesProperties (from
  guess/nodesproperties.go -> fromnodes.go)
- CR builders: CreateOrUpdateEC2NodeClass, CreateOrUpdateNodePool
  (from cluster/k8s/{ec2nodeclass,nodepool}.go)

`cluster/k8s/` is gone (it was misnamed: those files build Karpenter
CRDs, they aren't generic k8s primitives). `common/k8s/` keeps its
narrow scope: generic object CRUD + deployment-finder.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* kubectl-datadog: awsauth: extract ConfigMap name/namespace constants

`kube-system` and `aws-auth` each appeared 5 times across the three
functions. Promote them to package-level constants so the package's
single-ConfigMap scope is explicit at a glance.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
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.

3 participants