Repository: kubernetes-sigs/node-feature-discovery
Pull request #2056 (2025-02-17 12:35:54)

Introduce memory.hugepages feature
I added `memory.hugepages`  feature with the following attributes:
* `enabled`  - true` if total number of huge pages (of any page size) have been configured, otherwise `false`
* `hugepages-<page-size>` - total number of huge pages (e.g., `hugepages-1Gi=16`)


k8s-ci-robot: Hi @mfranczy. Thanks for your PR.

I'm waiting for a [kubernetes-sigs](https://github.com/orgs/kubernetes-sigs/people) member to verify that this patch is reasonable to test. If it is, they should reply with `/ok-to-test` on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should [join the org](https://git.k8s.io/community/community-membership.md#member) to skip this step.

Once the patch is verified, the new status will be reflected by the `ok-to-test` label.

I understand the commands that are listed [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fnode-feature-discovery).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository.
</details>

mfranczy: /cc @ArangoGutierrez @marquiz 

@ChaoyiHuang please take a look as well.
ChaoyiHuang: > What is the use case for this? Hugepages should be available as available resources/capacity in the Node object

some product requires both 2MB and 1G size hugepages, it is good enough to check the initial capacity (boot parameter). how to allocate and recycle the hugepages should be the responsibility of the applications.

dynamic capacity detection during runtime is unpredicatble, and lead to contention if multiple applications demand hugepages. the issue should be addressed in resources allocation in scheduling.
mfranczy: @marquiz looks like I misunderstood the requirement from our environments. Sorry for that. I have to change the implementation, but still the `memory.hugepages` is something we need.

We require a pre-flight check on nodes to verify if huge pages are enabled, and if they are, we need information about configured page sizes. This helps determine whether the image is compatibile with the node. This should be done ahead of the scheduling phase. However, we don't need to check capacity or available huge page resources, as you pointed out, we can leave it to scheduler.
mfranczy: I updated the PR, as mentioned before, it's only to check if required page sizes have been configured on node, capacity / available resources is left to scheduler. 

We need this for image compatibility.

Patch:
diff --git a/Dockerfile_generator b/Dockerfile_generator
index ff51770ae..cc874bd57 100644
--- a/Dockerfile_generator
+++ b/Dockerfile_generator
@@ -3,7 +3,7 @@ FROM ${BUILDER_IMAGE} as builder
 
 # Install tools
 RUN --mount=type=cache,target=/go/pkg/mod/ \
-    go install github.com/vektra/mockery/v2@v2.52.2 && \
+    go install github.com/vektra/mockery/v2@v2.42.0 && \
     go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.16.3 && \
     go install golang.org/x/tools/cmd/goimports@v0.25.0
 
diff --git a/Makefile b/Makefile
index 04cd39d83..ed6c10df9 100644
--- a/Makefile
+++ b/Makefile
@@ -8,7 +8,7 @@ IMAGE_BUILD_CMD ?= docker build
 IMAGE_BUILD_EXTRA_OPTS ?=
 IMAGE_PUSH_CMD ?= docker push
 CONTAINER_RUN_CMD ?= docker run
-BUILDER_IMAGE ?= golang:1.24-bookworm
+BUILDER_IMAGE ?= golang:1.23-bookworm
 BASE_IMAGE_FULL ?= debian:bookworm-slim
 BASE_IMAGE_MINIMAL ?= scratch
 
diff --git a/README.md b/README.md
index 709403e5a..c41439398 100644
--- a/README.md
+++ b/README.md
@@ -12,9 +12,8 @@ features and system configuration!
 #### Quick-start – the short-short version
 
 ```bash
-$ kubectl apply -k "https://github.com/kubernetes-sigs/node-feature-discovery/deployment/overlays/default?ref=v0.17.2"
+$ kubectl apply -k "https://github.com/kubernetes-sigs/node-feature-discovery/deployment/overlays/default?ref=v0.17.1
   namespace/node-feature-discovery created
-  customresourcedefinition.apiextensions.k8s.io/nodefeaturegroups.nfd.k8s-sigs.io created
   customresourcedefinition.apiextensions.k8s.io/nodefeaturerules.nfd.k8s-sigs.io created
   customresourcedefinition.apiextensions.k8s.io/nodefeatures.nfd.k8s-sigs.io created
   serviceaccount/nfd-gc created
@@ -26,8 +25,8 @@ $ kubectl apply -k "https://github.com/kubernetes-sigs/node-feature-discovery/de
   rolebinding.rbac.authorization.k8s.io/nfd-worker created
   clusterrolebinding.rbac.authorization.k8s.io/nfd-gc created
   clusterrolebinding.rbac.authorization.k8s.io/nfd-master created
-  configmap/nfd-master-conf-9mfc26f2tc created
-  configmap/nfd-worker-conf-c2mbm9t788 created
+  configmap/nfd-master-conf created
+  configmap/nfd-worker-conf created
   deployment.apps/nfd-gc created
   deployment.apps/nfd-master created
   daemonset.apps/nfd-worker created
diff --git a/Tiltfile b/Tiltfile
index 696810584..e5fe0dded 100644
--- a/Tiltfile
+++ b/Tiltfile
@@ -2,7 +2,7 @@
 
 BASE_IMAGE_MINIMAL="gcr.io/distroless/base"
 BASE_IMAGE_FULL="debian:bullseye-slim"
-BUILDER_IMAGE="golang:1.24-bookworm"
+BUILDER_IMAGE="golang:1.23-bookworm"
 HOSTMOUNT_PREFIX="/host-"
 IMAGE_TAG_NAME = os.getenv('IMAGE_TAG_NAME', "master")
 IMAGE_REGISTRY = os.getenv('IMAGE_REGISTRY', "gcr.io/k8s-staging-nfd")
diff --git a/api/generated/clientset/versioned/clientset.go b/api/generated/clientset/versioned/clientset.go
index 72ec0f5e1..44f129201 100644
--- a/api/generated/clientset/versioned/clientset.go
+++ b/api/generated/clientset/versioned/clientset.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/clientset/versioned/fake/clientset_generated.go b/api/generated/clientset/versioned/fake/clientset_generated.go
index aff6b01f4..635125b6a 100644
--- a/api/generated/clientset/versioned/fake/clientset_generated.go
+++ b/api/generated/clientset/versioned/fake/clientset_generated.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/clientset/versioned/fake/doc.go b/api/generated/clientset/versioned/fake/doc.go
index ac8c1ec9e..c8342d4bd 100644
--- a/api/generated/clientset/versioned/fake/doc.go
+++ b/api/generated/clientset/versioned/fake/doc.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/clientset/versioned/fake/register.go b/api/generated/clientset/versioned/fake/register.go
index 4b8db01ff..3c4d45a31 100644
--- a/api/generated/clientset/versioned/fake/register.go
+++ b/api/generated/clientset/versioned/fake/register.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/clientset/versioned/scheme/doc.go b/api/generated/clientset/versioned/scheme/doc.go
index 9e531af56..0fe2de913 100644
--- a/api/generated/clientset/versioned/scheme/doc.go
+++ b/api/generated/clientset/versioned/scheme/doc.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/clientset/versioned/scheme/register.go b/api/generated/clientset/versioned/scheme/register.go
index fbdcdfca9..f822ef608 100644
--- a/api/generated/clientset/versioned/scheme/register.go
+++ b/api/generated/clientset/versioned/scheme/register.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/clientset/versioned/typed/nfd/v1alpha1/doc.go b/api/generated/clientset/versioned/typed/nfd/v1alpha1/doc.go
index 71824ed54..ecc546221 100644
--- a/api/generated/clientset/versioned/typed/nfd/v1alpha1/doc.go
+++ b/api/generated/clientset/versioned/typed/nfd/v1alpha1/doc.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/doc.go b/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/doc.go
index 18420d452..d9bd9db27 100644
--- a/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/doc.go
+++ b/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/doc.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nfd_client.go b/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nfd_client.go
index 5ce0c4ad3..e84e6e3e1 100644
--- a/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nfd_client.go
+++ b/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nfd_client.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeature.go b/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeature.go
index efe9f63bc..a7356c9c8 100644
--- a/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeature.go
+++ b/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeature.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeaturegroup.go b/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeaturegroup.go
index 94e2ea890..cc4ae1070 100644
--- a/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeaturegroup.go
+++ b/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeaturegroup.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeaturerule.go b/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeaturerule.go
index 515a02733..6986116dc 100644
--- a/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeaturerule.go
+++ b/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeaturerule.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/clientset/versioned/typed/nfd/v1alpha1/generated_expansion.go b/api/generated/clientset/versioned/typed/nfd/v1alpha1/generated_expansion.go
index 2e25d3c7c..02d3e3518 100644
--- a/api/generated/clientset/versioned/typed/nfd/v1alpha1/generated_expansion.go
+++ b/api/generated/clientset/versioned/typed/nfd/v1alpha1/generated_expansion.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/clientset/versioned/typed/nfd/v1alpha1/nfd_client.go b/api/generated/clientset/versioned/typed/nfd/v1alpha1/nfd_client.go
index 1529f40c6..4776a6c83 100644
--- a/api/generated/clientset/versioned/typed/nfd/v1alpha1/nfd_client.go
+++ b/api/generated/clientset/versioned/typed/nfd/v1alpha1/nfd_client.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeature.go b/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeature.go
index ce5125a4c..70b854046 100644
--- a/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeature.go
+++ b/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeature.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturegroup.go b/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturegroup.go
index ab226adf2..cdee1eb7b 100644
--- a/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturegroup.go
+++ b/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturegroup.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturerule.go b/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturerule.go
index e976325b2..cf0719ad1 100644
--- a/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturerule.go
+++ b/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturerule.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/informers/externalversions/factory.go b/api/generated/informers/externalversions/factory.go
index 0174d7fd4..0bc947593 100644
--- a/api/generated/informers/externalversions/factory.go
+++ b/api/generated/informers/externalversions/factory.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/informers/externalversions/generic.go b/api/generated/informers/externalversions/generic.go
index 45f55ec36..1422eb95c 100644
--- a/api/generated/informers/externalversions/generic.go
+++ b/api/generated/informers/externalversions/generic.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/informers/externalversions/internalinterfaces/factory_interfaces.go b/api/generated/informers/externalversions/internalinterfaces/factory_interfaces.go
index 619766590..7f1153741 100644
--- a/api/generated/informers/externalversions/internalinterfaces/factory_interfaces.go
+++ b/api/generated/informers/externalversions/internalinterfaces/factory_interfaces.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/informers/externalversions/nfd/interface.go b/api/generated/informers/externalversions/nfd/interface.go
index b83e407ce..8c6835831 100644
--- a/api/generated/informers/externalversions/nfd/interface.go
+++ b/api/generated/informers/externalversions/nfd/interface.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/informers/externalversions/nfd/v1alpha1/interface.go b/api/generated/informers/externalversions/nfd/v1alpha1/interface.go
index 47163ad89..ea861a472 100644
--- a/api/generated/informers/externalversions/nfd/v1alpha1/interface.go
+++ b/api/generated/informers/externalversions/nfd/v1alpha1/interface.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/informers/externalversions/nfd/v1alpha1/nodefeature.go b/api/generated/informers/externalversions/nfd/v1alpha1/nodefeature.go
index 4341709a7..34e14e434 100644
--- a/api/generated/informers/externalversions/nfd/v1alpha1/nodefeature.go
+++ b/api/generated/informers/externalversions/nfd/v1alpha1/nodefeature.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/informers/externalversions/nfd/v1alpha1/nodefeaturegroup.go b/api/generated/informers/externalversions/nfd/v1alpha1/nodefeaturegroup.go
index 301123607..30559f5ce 100644
--- a/api/generated/informers/externalversions/nfd/v1alpha1/nodefeaturegroup.go
+++ b/api/generated/informers/externalversions/nfd/v1alpha1/nodefeaturegroup.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/informers/externalversions/nfd/v1alpha1/nodefeaturerule.go b/api/generated/informers/externalversions/nfd/v1alpha1/nodefeaturerule.go
index bc83a1480..37ad15dce 100644
--- a/api/generated/informers/externalversions/nfd/v1alpha1/nodefeaturerule.go
+++ b/api/generated/informers/externalversions/nfd/v1alpha1/nodefeaturerule.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/listers/nfd/v1alpha1/expansion_generated.go b/api/generated/listers/nfd/v1alpha1/expansion_generated.go
index 943ba3d55..5890048ee 100644
--- a/api/generated/listers/nfd/v1alpha1/expansion_generated.go
+++ b/api/generated/listers/nfd/v1alpha1/expansion_generated.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/listers/nfd/v1alpha1/nodefeature.go b/api/generated/listers/nfd/v1alpha1/nodefeature.go
index 348d294a2..f670b6e8a 100644
--- a/api/generated/listers/nfd/v1alpha1/nodefeature.go
+++ b/api/generated/listers/nfd/v1alpha1/nodefeature.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/listers/nfd/v1alpha1/nodefeaturegroup.go b/api/generated/listers/nfd/v1alpha1/nodefeaturegroup.go
index 1f38d8878..a59e53684 100644
--- a/api/generated/listers/nfd/v1alpha1/nodefeaturegroup.go
+++ b/api/generated/listers/nfd/v1alpha1/nodefeaturegroup.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/generated/listers/nfd/v1alpha1/nodefeaturerule.go b/api/generated/listers/nfd/v1alpha1/nodefeaturerule.go
index 4faea9b70..77cdcf0cb 100644
--- a/api/generated/listers/nfd/v1alpha1/nodefeaturerule.go
+++ b/api/generated/listers/nfd/v1alpha1/nodefeaturerule.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/api/nfd/v1alpha1/zz_generated.deepcopy.go b/api/nfd/v1alpha1/zz_generated.deepcopy.go
index 1ed2a816a..491d9866c 100644
--- a/api/nfd/v1alpha1/zz_generated.deepcopy.go
+++ b/api/nfd/v1alpha1/zz_generated.deepcopy.go
@@ -2,7 +2,7 @@
 // +build !ignore_autogenerated
 
 /*
-Copyright 2025 The Kubernetes Authors.
+Copyright 2024 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/cmd/nfd-master/main.go b/cmd/nfd-master/main.go
index 774b47335..cec1a0b83 100644
--- a/cmd/nfd-master/main.go
+++ b/cmd/nfd-master/main.go
@@ -108,8 +108,10 @@ func initFlags(flagset *flag.FlagSet) (*master.Args, *master.ConfigOverrideArgs)
 		"Config file to use.")
 	flagset.StringVar(&args.Kubeconfig, "kubeconfig", "",
 		"Kubeconfig to use")
-	flagset.IntVar(&args.Port, "port", 8080,
-		"Port which metrics and healthz endpoints are served on")
+	flagset.IntVar(&args.MetricsPort, "metrics", 8081,
+		"Port on which to expose metrics.")
+	flagset.IntVar(&args.GrpcHealthPort, "grpc-health", 8082,
+		"Port on which to expose the grpc health endpoint.")
 	flagset.BoolVar(&args.Prune, "prune", false,
 		"Prune all NFD related attributes from all nodes of the cluster and exit.")
 	flagset.StringVar(&args.Options, "options", "",
diff --git a/cmd/nfd-topology-updater/main.go b/cmd/nfd-topology-updater/main.go
index feafd58f5..c59432ec5 100644
--- a/cmd/nfd-topology-updater/main.go
+++ b/cmd/nfd-topology-updater/main.go
@@ -107,8 +107,10 @@ func initFlags(flagset *flag.FlagSet) (*topology.Args, *resourcemonitor.Args) {
 		"Do not create or update NodeResourceTopology objects.")
 	flagset.StringVar(&args.KubeConfigFile, "kubeconfig", "",
 		"Kube config file.")
-	flagset.IntVar(&args.Port, "port", 8080,
-		"Port which metrics and healthz endpoints are served on")
+	flagset.IntVar(&args.MetricsPort, "metrics", 8081,
+		"Port on which to expose metrics.")
+	flagset.IntVar(&args.GrpcHealthPort, "grpc-health", 8082,
+		"Port on which to expose the grpc health endpoint.")
 	flagset.DurationVar(&resourcemonitorArgs.SleepInterval, "sleep-interval", time.Duration(60)*time.Second,
 		"Time to sleep between CR updates. zero means no CR updates on interval basis. [Default: 60s]")
 	flagset.StringVar(&resourcemonitorArgs.Namespace, "watch-namespace", "*",
diff --git a/cmd/nfd-worker/main.go b/cmd/nfd-worker/main.go
index 120db537a..c92bfab1f 100644
--- a/cmd/nfd-worker/main.go
+++ b/cmd/nfd-worker/main.go
@@ -108,8 +108,10 @@ func initFlags(flagset *flag.FlagSet) (*worker.Args, *worker.ConfigOverrideArgs)
 		"Kubeconfig to use")
 	flagset.BoolVar(&args.Oneshot, "oneshot", false,
 		"Do not publish feature labels")
-	flagset.IntVar(&args.Port, "port", 8080,
-		"Port on which to metrics and healthz endpoints are served")
+	flagset.IntVar(&args.MetricsPort, "metrics", 8081,
+		"Port on which to expose metrics.")
+	flagset.IntVar(&args.GrpcHealthPort, "grpc-health", 8082,
+		"Port on which to expose the grpc health endpoint.")
 	flagset.StringVar(&args.Options, "options", "",
 		"Specify config options from command line. Config options are specified "+
 			"in the same format as in the config file (i.e. json or yaml). These options")
diff --git a/deployment/base/master/master-deployment.yaml b/deployment/base/master/master-deployment.yaml
index 6d066fe78..f4c560e9a 100644
--- a/deployment/base/master/master-deployment.yaml
+++ b/deployment/base/master/master-deployment.yaml
@@ -33,16 +33,14 @@ spec:
               port: 8082
             failureThreshold: 30
           livenessProbe:
-            httpGet:
-              path: /healthz
-              port: http
+            grpc:
+              port: 8082
           readinessProbe:
-            httpGet:
-              path: /healthz
-              port: http
+            grpc:
+              port: 8082
             failureThreshold: 10
           command:
             - "nfd-master"
           ports:
-            - name: http
-              containerPort: 8080
+            - name: metrics
+              containerPort: 8081
diff --git a/deployment/base/topologyupdater-daemonset/topologyupdater-daemonset.yaml b/deployment/base/topologyupdater-daemonset/topologyupdater-daemonset.yaml
index 27d804b54..5d11e9b15 100644
--- a/deployment/base/topologyupdater-daemonset/topologyupdater-daemonset.yaml
+++ b/deployment/base/topologyupdater-daemonset/topologyupdater-daemonset.yaml
@@ -20,15 +20,13 @@ spec:
           image: gcr.io/k8s-staging-nfd/node-feature-discovery:master
           imagePullPolicy: Always
           livenessProbe:
-            httpGet:
-              path: /healthz
-              port: http
+            grpc:
+              port: 8082
             initialDelaySeconds: 10
             periodSeconds: 10
           readinessProbe:
-            httpGet:
-              path: /healthz
-              port: http
+            grpc:
+              port: 8082
             initialDelaySeconds: 5
             periodSeconds: 10
             failureThreshold: 10
@@ -43,5 +41,5 @@ spec:
               cpu: 50m
               memory: 40Mi
           ports:
-            - name: http
-              containerPort: 8080
+            - name: metrics
+              containerPort: 8081
diff --git a/deployment/base/worker-daemonset/worker-daemonset.yaml b/deployment/base/worker-daemonset/worker-daemonset.yaml
index dd429af51..f70a64388 100644
--- a/deployment/base/worker-daemonset/worker-daemonset.yaml
+++ b/deployment/base/worker-daemonset/worker-daemonset.yaml
@@ -20,15 +20,13 @@ spec:
           image: gcr.io/k8s-staging-nfd/node-feature-discovery:master
           imagePullPolicy: Always
           livenessProbe:
-            httpGet:
-              path: /healthz
-              port: http
+            grpc:
+              port: 8082
             initialDelaySeconds: 10
             periodSeconds: 10
           readinessProbe:
-            httpGet:
-              path: /healthz
-              port: http
+            grpc:
+              port: 8082
             initialDelaySeconds: 5
             periodSeconds: 10
             failureThreshold: 10
@@ -42,5 +40,5 @@ spec:
               cpu: 5m
               memory: 64Mi
           ports:
-            - name: http
-              containerPort: 8080
+            - name: metrics
+              containerPort: 8081
diff --git a/deployment/helm/node-feature-discovery/templates/master.yaml b/deployment/helm/node-feature-discovery/templates/master.yaml
index 7756b9e9f..da3ca2408 100644
--- a/deployment/helm/node-feature-discovery/templates/master.yaml
+++ b/deployment/helm/node-feature-discovery/templates/master.yaml
@@ -29,7 +29,6 @@ spec:
         {{- toYaml . | nindent 8 }}
         {{- end }}
     spec:
-      dnsPolicy: {{ .Values.master.dnsPolicy }}
     {{- with .Values.priorityClassName }}
       priorityClassName: {{ . }}
     {{- end }}
@@ -49,9 +48,8 @@ spec:
           image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
           imagePullPolicy: {{ .Values.image.pullPolicy }}
           startupProbe:
-            httpGet:
-              path: /healthz
-              port: http
+            grpc:
+              port: {{ .Values.master.healthPort | default "8082" }}
           {{- with .Values.master.startupProbe.initialDelaySeconds }}
             initialDelaySeconds: {{ . }}
           {{- end }}
@@ -65,9 +63,8 @@ spec:
             timeoutSeconds: {{ . }}
           {{- end }}
           livenessProbe:
-            httpGet:
-              path: /healthz
-              port: http
+            grpc:
+              port: {{ .Values.master.healthPort | default "8082" }}
           {{- with .Values.master.livenessProbe.initialDelaySeconds }}
             initialDelaySeconds: {{ . }}
           {{- end }}
@@ -81,9 +78,8 @@ spec:
             timeoutSeconds: {{ . }}
           {{- end }}
           readinessProbe:
-            httpGet:
-              path: /healthz
-              port: http
+            grpc:
+              port: {{ .Values.master.healthPort | default "8082" }}
           {{- with .Values.master.readinessProbe.initialDelaySeconds }}
             initialDelaySeconds: {{ . }}
           {{- end }}
@@ -100,8 +96,10 @@ spec:
             successThreshold: {{ . }}
           {{- end }}
           ports:
-          - containerPort: {{ .Values.master.port | default "8080" }}
-            name: http
+          - containerPort: {{ .Values.master.metricsPort | default "8081" }}
+            name: metrics
+          - containerPort: {{ .Values.master.healthPort | default "8082" }}
+            name: health
           env:
           - name: NODE_NAME
             valueFrom:
@@ -141,7 +139,8 @@ spec:
             {{- range $key, $value := .Values.featureGates }}
             - "-feature-gates={{ $key }}={{ $value }}"
             {{- end }}
-            - "-port={{ .Values.master.port | default "8080" }}"
+            - "-metrics={{ .Values.master.metricsPort  | default "8081" }}"
+            - "-grpc-health={{ .Values.master.healthPort | default "8082" }}"
             {{- with .Values.master.extraArgs }}
             {{- toYaml . | nindent 12 }}
             {{- end }}
diff --git a/deployment/helm/node-feature-discovery/templates/nfd-gc.yaml b/deployment/helm/node-feature-discovery/templates/nfd-gc.yaml
index f3489b236..3642aa642 100644
--- a/deployment/helm/node-feature-discovery/templates/nfd-gc.yaml
+++ b/deployment/helm/node-feature-discovery/templates/nfd-gc.yaml
@@ -29,7 +29,7 @@ spec:
       {{- end }}
     spec:
       serviceAccountName: {{ include "node-feature-discovery.gc.serviceAccountName" . }}
-      dnsPolicy: {{ .Values.gc.dnsPolicy }}
+      dnsPolicy: ClusterFirstWithHostNet
     {{- with .Values.priorityClassName }}
       priorityClassName: {{ . }}
     {{- end }}
diff --git a/deployment/helm/node-feature-discovery/templates/topologyupdater.yaml b/deployment/helm/node-feature-discovery/templates/topologyupdater.yaml
index 5a4d7b3dc..9a466f88e 100644
--- a/deployment/helm/node-feature-discovery/templates/topologyupdater.yaml
+++ b/deployment/helm/node-feature-discovery/templates/topologyupdater.yaml
@@ -29,7 +29,7 @@ spec:
         {{- end }}
     spec:
       serviceAccountName: {{ include "node-feature-discovery.topologyUpdater.serviceAccountName" . }}
-      dnsPolicy: {{ .Values.topologyUpdater.dnsPolicy }}
+      dnsPolicy: ClusterFirstWithHostNet
     {{- with .Values.priorityClassName }}
       priorityClassName: {{ . }}
     {{- end }}
@@ -45,9 +45,8 @@ spec:
         image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
         imagePullPolicy: "{{ .Values.image.pullPolicy }}"
         livenessProbe:
-          httpGet:
-            path: /healthz
-            port: http
+          grpc:
+            port: {{ .Values.topologyUpdater.healthPort | default "8082" }}
         {{- with .Values.topologyUpdater.livenessProbe.initialDelaySeconds }}
           initialDelaySeconds: {{ . }}
         {{- end }}
@@ -61,9 +60,8 @@ spec:
           timeoutSeconds: {{ . }}
         {{- end }}
         readinessProbe:
-          httpGet:
-            path: /healthz
-            port: http
+          grpc:
+            port: {{ .Values.topologyUpdater.healthPort | default "8082" }}
         {{- with .Values.topologyUpdater.readinessProbe.initialDelaySeconds }}
           initialDelaySeconds: {{ . }}
         {{- end }}
@@ -115,13 +113,16 @@ spec:
           # Disable kubelet state tracking by giving an empty path
           - "-kubelet-state-dir="
           {{- end }}
-          - "-port={{ .Values.topologyUpdater.port | default "8080"}}"
+          - "-metrics={{ .Values.topologyUpdater.metricsPort | default "8081"}}"
+          - "-grpc-health={{ .Values.topologyUpdater.healthPort | default "8082" }}"
           {{- with .Values.topologyUpdater.extraArgs }}
           {{- toYaml . | nindent 10 }}
           {{- end }}
         ports:
-          - containerPort: {{ .Values.topologyUpdater.port | default "8080"}}
-            name: http
+          - containerPort: {{ .Values.topologyUpdater.metricsPort | default "8081"}}
+            name: metrics
+          - containerPort: {{ .Values.topologyUpdater.healthPort | default "8082" }}
+            name: health
         volumeMounts:
         {{- if .Values.topologyUpdater.kubeletConfigPath | empty | not }}
         - name: kubelet-config
diff --git a/deployment/helm/node-feature-discovery/templates/worker.yaml b/deployment/helm/node-feature-discovery/templates/worker.yaml
index b8399f098..5fd1ab744 100644
--- a/deployment/helm/node-feature-discovery/templates/worker.yaml
+++ b/deployment/helm/node-feature-discovery/templates/worker.yaml
@@ -28,7 +28,7 @@ spec:
         {{- toYaml . | nindent 8 }}
         {{- end }}
     spec:
-      dnsPolicy: {{ .Values.worker.dnsPolicy }}
+      dnsPolicy: ClusterFirstWithHostNet
     {{- with .Values.priorityClassName }}
       priorityClassName: {{ . }}
     {{- end }}
@@ -47,9 +47,8 @@ spec:
         image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
         imagePullPolicy: {{ .Values.image.pullPolicy }}
         livenessProbe:
-          httpGet:
-            path: /healthz
-            port: http
+          grpc:
+            port: {{ .Values.worker.healthPort | default "8082" }}
         {{- with .Values.worker.livenessProbe.initialDelaySeconds }}
           initialDelaySeconds: {{ . }}
         {{- end }}
@@ -63,9 +62,8 @@ spec:
           timeoutSeconds: {{ . }}
         {{- end }}
         readinessProbe:
-          httpGet:
-            path: /healthz
-            port: http
+          grpc:
+            port: {{ .Values.worker.healthPort | default "8082" }}
         {{- with .Values.worker.readinessProbe.initialDelaySeconds }}
           initialDelaySeconds: {{ . }}
         {{- end }}
@@ -106,13 +104,16 @@ spec:
         {{- range $key, $value := .Values.featureGates }}
         - "-feature-gates={{ $key }}={{ $value }}"
         {{- end }}
-        - "-port={{ .Values.worker.port | default "8080"}}"
-        {{- with .Values.worker.extraArgs }}
+        - "-metrics={{ .Values.worker.metricsPort | default "8081"}}"
+        - "-grpc-health={{ .Values.worker.healthPort | default "8082" }}"
+        {{- with .Values.gc.extraArgs }}
         {{- toYaml . | nindent 8 }}
         {{- end }}
         ports:
-          - containerPort: {{ .Values.worker.port | default "8080"}}
-            name: http
+          - containerPort: {{ .Values.worker.metricsPort | default "8081"}}
+            name: metrics
+          - containerPort: {{ .Values.worker.healthPort | default "8082" }}
+            name: health
         volumeMounts:
         - name: host-boot
           mountPath: "/host-boot"
diff --git a/deployment/helm/node-feature-discovery/values.yaml b/deployment/helm/node-feature-discovery/values.yaml
index 1b3225d62..68440f9c6 100644
--- a/deployment/helm/node-feature-discovery/values.yaml
+++ b/deployment/helm/node-feature-discovery/values.yaml
@@ -20,7 +20,6 @@ master:
   extraArgs: []
   extraEnvs: []
   hostNetwork: false
-  dnsPolicy: ClusterFirstWithHostNet
   config: ### <NFD-MASTER-CONF-START-DO-NOT-REMOVE>
     # noPublish: false
     # autoDefaultNs: true
@@ -67,7 +66,8 @@ master:
     #   retryPeriod: 2s
     # nfdApiParallelism: 10
   ### <NFD-MASTER-CONF-END-DO-NOT-REMOVE>
-  port: 8080
+  metricsPort: 8081
+  healthPort: 8082
   instance:
   featureApi:
   resyncPeriod:
@@ -148,14 +148,20 @@ master:
                 values: [""]
                 
   startupProbe:
+    grpc:
+      port: 8082
     failureThreshold: 30
     # periodSeconds: 10
-  livenessProbe: {}
+  livenessProbe:
+    grpc:
+      port: 8082
     # failureThreshold: 3
     # initialDelaySeconds: 0
     # periodSeconds: 10
     # timeoutSeconds: 1
   readinessProbe:
+    grpc:
+      port: 8082
     failureThreshold: 10
     # initialDelaySeconds: 0
     # periodSeconds: 10
@@ -167,7 +173,6 @@ worker:
   extraArgs: []
   extraEnvs: []
   hostNetwork: false
-  dnsPolicy: ClusterFirstWithHostNet
   config: ### <NFD-WORKER-CONF-START-DO-NOT-REMOVE>
     #core:
     #  labelWhiteList:
@@ -411,7 +416,8 @@ worker:
     #          matchName: {op: In, value: ["SWAP", "X86", "ARM"]}
 ### <NFD-WORKER-CONF-END-DO-NOT-REMOVE>
 
-  port: 8080
+  metricsPort: 8081
+  healthPort: 8082
   daemonsetAnnotations: {}
   podSecurityContext: {}
     # fsGroup: 2000
@@ -425,11 +431,15 @@ worker:
     # runAsUser: 1000
 
   livenessProbe:
+    grpc:
+      port: 8082
     initialDelaySeconds: 10
     # failureThreshold: 3
     # periodSeconds: 10
     # timeoutSeconds: 1
   readinessProbe:
+    grpc:
+      port: 8082
     initialDelaySeconds: 5
     failureThreshold: 10
     # periodSeconds: 10
@@ -489,7 +499,6 @@ topologyUpdater:
   extraArgs: []
   extraEnvs: []
   hostNetwork: false
-  dnsPolicy: ClusterFirstWithHostNet
 
   serviceAccount:
     create: true
@@ -502,7 +511,8 @@ topologyUpdater:
   rbac:
     create: true
 
-  port: 8080
+  metricsPort: 8081
+  healthPort: 8082
   kubeletConfigPath:
   kubeletPodResourcesSockPath:
   updateInterval: 60s
@@ -516,13 +526,17 @@ topologyUpdater:
       drop: [ "ALL" ]
     readOnlyRootFilesystem: true
     runAsUser: 0
-
+  
   livenessProbe:
+    grpc:
+      port: 8082
     initialDelaySeconds: 10
     # failureThreshold: 3
     # periodSeconds: 10
     # timeoutSeconds: 1
   readinessProbe:
+    grpc:
+      port: 8082
     initialDelaySeconds: 5
     failureThreshold: 10
     # periodSeconds: 10
@@ -549,7 +563,6 @@ gc:
   extraEnvs: []
   hostNetwork: false
   replicaCount: 1
-  dnsPolicy: ClusterFirstWithHostNet
 
   serviceAccount:
     create: true
diff --git a/docs/deployment/helm.md b/docs/deployment/helm.md
index 734f362a8..cdcf4ca72 100644
--- a/docs/deployment/helm.md
+++ b/docs/deployment/helm.md
@@ -176,7 +176,8 @@ API's you need to install the prometheus operator in your cluster.
 | `master.*`                                  | dict    |                                  | NFD master deployment configuration                                                                                                                                                                   |
 | `master.enable`                             | bool    | true                             | Specifies whether nfd-master should be deployed                                                                                                                                                       |
 | `master.hostNetwork`                        | bool    | false                            | Specifies whether to enable or disable running the container in the host's network namespace                                                                                                          |
-| `master.port`                               | integer | 8080                             | Port on which to serve http for metrics and healthz endpoints.                                                                                                                                        |
+| `master.metricsPort`                        | integer | 8081                             | Port on which to expose metrics from components to prometheus operator. **DEPRECATED**: will be replaced by `master.port` in NFD v0.18.                                                               |
+| `master.healthPort`                         | integer | 8082                             | Port on which to expose the grpc health endpoint, will be also used for the probes. **DEPRECATED**: will be replaced by `master.port` in NFD v0.18.                                                   |
 | `master.instance`                           | string  |                                  | Instance name. Used to separate annotation namespaces for multiple parallel deployments                                                                                                               |
 | `master.resyncPeriod`                       | string  |                                  | NFD API controller resync period.                                                                                                                                                                     |
 | `master.extraLabelNs`                       | array   | []                               | List of allowed extra label namespaces                                                                                                                                                                |
@@ -212,7 +213,6 @@ API's you need to install the prometheus operator in your cluster.
 | `master.readinessProbe.periodSeconds`       | integer | 10 (by Kubernetes)               | Specifies how often (in seconds) to perform the readiness probe.                                                                                                                                      |
 | `master.readinessProbe.timeoutSeconds`      | integer | 1 (by Kubernetes)                | Specifies the number of seconds after which the probe times out.                                                                                                                                      |
 | `master.readinessProbe.successThreshold`    | integer | 1 (by Kubernetes)                | Specifies the number of consecutive successes of readiness probes before considering the pod as ready.                                                                                                |
-| `master.dnsPolicy`                          | array   | ClusterFirstWithHostNet          | NFD master pod [dnsPolicy](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-s-dns-policy)                                                                                 |
 
 > `[0]` Additional info for `master.resources.requests`: \
 > You may want to use the same value for `requests.memory` and `limits.memory`.
@@ -232,7 +232,8 @@ API's you need to install the prometheus operator in your cluster.
 | `worker.*`                                  | dict    |                         | NFD worker daemonset configuration                                                                                                                                                                           |
 | `worker.enable`                             | bool    | true                    | Specifies whether nfd-worker should be deployed                                                                                                                                                              |
 | `worker.hostNetwork`                        | bool    | false                   | Specifies whether to enable or disable running the container in the host's network namespace                                                                                                                 |
-| `worker.port`                               | int     | 8080                    | Port on which to serve http for metrics and healthz endpoints.                                                                                                                                               |
+| `worker.metricsPort`                        | int     | 8081                    | Port on which to expose metrics from components to prometheus operator. **DEPRECATED**: will be replaced by `worker.port` in NFD v0.18.                                                                      |
+| `worker.healthPort`                         | int     | 8082                    | Port on which to expose the grpc health endpoint, will be also used for the probes. **DEPRECATED**: will be replaced by `worker.port` in NFD v0.18.                                                          |
 | `worker.config`                             | dict    |                         | NFD worker [configuration](../reference/worker-configuration-reference)                                                                                                                                      |
 | `worker.podSecurityContext`                 | dict    | {}                      | [PodSecurityContext](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod) holds pod-level security attributes and common container settins         |
 | `worker.securityContext`                    | dict    | {}                      | Container [security settings](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container)                                                           |
@@ -260,7 +261,6 @@ API's you need to install the prometheus operator in your cluster.
 | `worker.readinessProbe.periodSeconds`       | integer | 10 (by Kubernetes)      | Specifies how often (in seconds) to perform the readiness probe.                                                                                                                                             |
 | `worker.readinessProbe.timeoutSeconds`      | integer | 1 (by Kubernetes)       | Specifies the number of seconds after which the probe times out.                                                                                                                                             |
 | `worker.readinessProbe.successThreshold`    | integer | 1 (by Kubernetes)       | Specifies the number of consecutive successes of readiness probes before considering the pod as ready.                                                                                                       |
-| `worker.dnsPolicy`                          | array   | ClusterFirstWithHostNet | NFD worker pod [dnsPolicy](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-s-dns-policy)                                                                                        |
 
 ### Topology updater parameters
 
@@ -274,7 +274,8 @@ API's you need to install the prometheus operator in your cluster.
 | `topologyUpdater.serviceAccount.annotations`         | dict    | {}                       | Annotations to add to the service account for topology updater                                                                                                                                              |
 | `topologyUpdater.serviceAccount.name`                | string  |                          | The name of the service account for topology updater to use. If not set and create is true, a name is generated using the fullname template and `-topology-updater` suffix                                  |
 | `topologyUpdater.rbac.create`                        | bool    | true                     | Specifies whether to create [RBAC][rbac] configuration for topology updater                                                                                                                                 |
-| `topologyUpdater.port`                               | integer | 8080                     | Port on which to serve http for metrics and healthz endpoints.                                                                                                                                              |
+| `topologyUpdater.metricsPort`                        | integer | 8081                     | Port on which to expose prometheus metrics. **DEPRECATED**: will be replaced by `topologyUpdater.port` in NFD v0.18.                                                                                        |
+| `topologyUpdater.healthPort`                         | integer | 8082                     | Port on which to expose the grpc health endpoint, will be also used for the probes. **DEPRECATED**: will be replaced by `topologyUpdater.port` in NFD v0.18.                                                |
 | `topologyUpdater.kubeletConfigPath`                  | string  | ""                       | Specifies the kubelet config host path                                                                                                                                                                      |
 | `topologyUpdater.kubeletPodResourcesSockPath`        | string  | ""                       | Specifies the kubelet sock path to read pod resources                                                                                                                                                       |
 | `topologyUpdater.updateInterval`                     | string  | 60s                      | Time to sleep between CR updates. Non-positive value implies no CR update.                                                                                                                                  |
@@ -303,7 +304,6 @@ API's you need to install the prometheus operator in your cluster.
 | `topologyUpdater.readinessProbe.periodSeconds`       | integer | 10 (by Kubernetes)       | Specifies how often (in seconds) to perform the readiness probe.                                                                                                                                            |
 | `topologyUpdater.readinessProbe.timeoutSeconds`      | integer | 1 (by Kubernetes)        | Specifies the number of seconds after which the probe times out.                                                                                                                                            |
 | `topologyUpdater.readinessProbe.successThreshold`    | integer | 1 (by Kubernetes)        | Specifies the number of consecutive successes of readiness probes before considering the pod as ready.                                                                                                      |
-| `topologyUpdater.dnsPolicy`                          | array   | ClusterFirstWithHostNet  | Topology updater pod [dnsPolicy](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-s-dns-policy)                                                                                 |
 
 ### Garbage collector parameters
 
@@ -329,7 +329,6 @@ API's you need to install the prometheus operator in your cluster.
 | `gc.extraArgs`                  | array   | []                        | Additional [command line arguments](../reference/gc-commandline-reference.md) to pass to nfd-gc                                                                                                       |
 | `gc.extraEnvs`                  | array   | []                        | Additional environment variables to pass to nfd-gc                                                                                                                                                    |
 | `gc.revisionHistoryLimit`       | integer |                           | Specify how many old ReplicaSets for this Deployment you want to retain. [revisionHistoryLimit](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#revision-history-limit)         |
-| `gc.dnsPolicy`                  | array   | ClusterFirstWithHostNet   | Garbage collector pod [dnsPolicy](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-s-dns-policy)                                                                          |
 
 <!-- Links -->
 
diff --git a/docs/usage/customization-guide.md b/docs/usage/customization-guide.md
index aa0b9ff80..b85b72c07 100644
--- a/docs/usage/customization-guide.md
+++ b/docs/usage/customization-guide.md
@@ -966,6 +966,9 @@ The following features are available for matching:
 |                  |              | **`node_count`** | int | Number of NUMA nodes |
 | **`memory.swap`**  | attribute  |          |            | Swap enabled on node |
 |                  |              | **`enabled`** | bool  | `true` if swap partition detected, `false` otherwise |
+| **`memory.hugepages`**  | attribute  |          |       | Discovery of supported huge pages size on node |
+|                  |              | **`enabled`** | bool  | `true` if total number of huge pages (of any page size) have been configured, otherwise `false` |
+|                  |              | **`hugepages-<page-size>`** | string   | total number of huge pages (e.g., `hugepages-1Gi=16`) |
 | **`network.device`** | instance |          |            | Physical (non-virtual) network interfaces present in the system |
 |                  |              | **`name`** | string   | Name of the network interface |
 |                  |              | **`<sysfs-attribute>`** | string | Sysfs network interface attribute, available attributes: `operstate`, `speed`, `sriov_numvfs`, `sriov_totalvfs` |
@@ -1100,17 +1103,14 @@ these separate expansions would be created, i.e. the end result would be a
 union of all the individual expansions.
 
 Rule templates use the Golang [text/template](https://pkg.go.dev/text/template)
-package along with [Sprig functions](https://masterminds.github.io/sprig/)
-and all their functionality (e.g. pipelines and functions) can
+package and all its built-in functionality (e.g. pipelines and functions) can
 be used. An example template taking use of the built-in `len` function,
-advertising the number of PCI network controllers from a specific vendor,
-and using Sprig's `first`, `trim` and `substr` to advertise the first one's class:
+advertising the number of PCI network controllers from a specific vendor:
 <!-- {% raw %} -->
 
 ```yaml
     labelsTemplate: |
       num-intel-network-controllers={{ .pci.device | len }}
-      first-intel-network-controllers={{ (.pci.device | first).class | trim | substr 0 63 }}
     matchFeatures:
       - feature: pci.device
         matchExpressions:
@@ -1120,7 +1120,6 @@ and using Sprig's `first`, `trim` and `substr` to advertise the first one's clas
 ```
 
 <!-- {% endraw %} -->
-
 Imaginative template pipelines are possible, but care must be taken to
 produce understandable and maintainable rule sets.
 
diff --git a/examples/grafana-dashboard.json b/examples/grafana-dashboard.json
index 25db5995e..e9cd95dec 100644
--- a/examples/grafana-dashboard.json
+++ b/examples/grafana-dashboard.json
@@ -1,28 +1,4 @@
 {
-  "__inputs": [
-    {
-      "name": "DS_PROMETHEUS",
-      "label": "Prometheus",
-      "description": "",
-      "type": "datasource",
-      "pluginId": "prometheus",
-      "pluginName": "Prometheus"
-    }
-  ],
-  "__requires": [
-    {
-      "type": "grafana",
-      "id": "grafana",
-      "name": "Grafana",
-      "version": "9.3.6"
-    },
-    {
-      "type": "datasource",
-      "id": "prometheus",
-      "name": "Prometheus",
-      "version": "1.0.0"
-    }
-  ],
   "annotations": {
     "list": [
       {
@@ -42,14 +18,14 @@
   "editable": true,
   "fiscalYearStartMonth": 0,
   "graphTooltip": 0,
-  "id": null,
+  "id": 30,
   "links": [],
   "liveNow": false,
   "panels": [
     {
       "datasource": {
         "type": "prometheus",
-        "uid": "${DS_PROMETHEUS}"
+        "uid": "prometheus"
       },
       "fieldConfig": {
         "defaults": {
@@ -100,7 +76,7 @@
         {
           "datasource": {
             "type": "prometheus",
-            "uid": "${DS_PROMETHEUS}"
+            "uid": "prometheus"
           },
           "disableTextWrap": false,
           "editorMode": "builder",
@@ -120,7 +96,7 @@
     {
       "datasource": {
         "type": "prometheus",
-        "uid": "${DS_PROMETHEUS}"
+        "uid": "prometheus"
       },
       "fieldConfig": {
         "defaults": {
@@ -171,7 +147,7 @@
         {
           "datasource": {
             "type": "prometheus",
-            "uid": "${DS_PROMETHEUS}"
+            "uid": "prometheus"
           },
           "disableTextWrap": false,
           "editorMode": "builder",
@@ -191,7 +167,7 @@
     {
       "datasource": {
         "type": "prometheus",
-        "uid": "${DS_PROMETHEUS}"
+        "uid": "prometheus"
       },
       "fieldConfig": {
         "defaults": {
@@ -242,7 +218,7 @@
         {
           "datasource": {
             "type": "prometheus",
-            "uid": "${DS_PROMETHEUS}"
+            "uid": "prometheus"
           },
           "disableTextWrap": false,
           "editorMode": "builder",
@@ -262,7 +238,7 @@
     {
       "datasource": {
         "type": "prometheus",
-        "uid": "${DS_PROMETHEUS}"
+        "uid": "prometheus"
       },
       "fieldConfig": {
         "defaults": {
@@ -313,7 +289,7 @@
         {
           "datasource": {
             "type": "prometheus",
-            "uid": "${DS_PROMETHEUS}"
+            "uid": "prometheus"
           },
           "disableTextWrap": false,
           "editorMode": "builder",
@@ -333,7 +309,7 @@
     {
       "datasource": {
         "type": "prometheus",
-        "uid": "${DS_PROMETHEUS}"
+        "uid": "prometheus"
       },
       "fieldConfig": {
         "defaults": {
@@ -411,7 +387,7 @@
         {
           "datasource": {
             "type": "prometheus",
-            "uid": "${DS_PROMETHEUS}"
+            "uid": "prometheus"
           },
           "disableTextWrap": false,
           "editorMode": "builder",
@@ -431,7 +407,7 @@
     {
       "datasource": {
         "type": "prometheus",
-        "uid": "${DS_PROMETHEUS}"
+        "uid": "prometheus"
       },
       "fieldConfig": {
         "defaults": {
@@ -509,7 +485,7 @@
         {
           "datasource": {
             "type": "prometheus",
-            "uid": "${DS_PROMETHEUS}"
+            "uid": "prometheus"
           },
           "disableTextWrap": false,
           "editorMode": "builder",
@@ -529,7 +505,7 @@
     {
       "datasource": {
         "type": "prometheus",
-        "uid": "${DS_PROMETHEUS}"
+        "uid": "prometheus"
       },
       "fieldConfig": {
         "defaults": {
@@ -607,7 +583,7 @@
         {
           "datasource": {
             "type": "prometheus",
-            "uid": "${DS_PROMETHEUS}"
+            "uid": "prometheus"
           },
           "editorMode": "builder",
           "expr": "nfd_master_node_update_failures_total",
@@ -622,7 +598,7 @@
     {
       "datasource": {
         "type": "prometheus",
-        "uid": "${DS_PROMETHEUS}"
+        "uid": "prometheus"
       },
       "fieldConfig": {
         "defaults": {
@@ -700,7 +676,7 @@
         {
           "datasource": {
             "type": "prometheus",
-            "uid": "${DS_PROMETHEUS}"
+            "uid": "prometheus"
           },
           "editorMode": "builder",
           "expr": "nfd_master_nodefeaturerule_processing_errors_total",
@@ -716,7 +692,7 @@
     {
       "datasource": {
         "type": "prometheus",
-        "uid": "${DS_PROMETHEUS}"
+        "uid": "prometheus"
       },
       "fieldConfig": {
         "defaults": {
@@ -794,7 +770,7 @@
         {
           "datasource": {
             "type": "prometheus",
-            "uid": "${DS_PROMETHEUS}"
+            "uid": "prometheus"
           },
           "disableTextWrap": false,
           "editorMode": "builder",
@@ -813,7 +789,7 @@
     {
       "datasource": {
         "type": "prometheus",
-        "uid": "${DS_PROMETHEUS}"
+        "uid": "prometheus"
       },
       "fieldConfig": {
         "defaults": {
@@ -891,7 +867,7 @@
         {
           "datasource": {
             "type": "prometheus",
-            "uid": "${DS_PROMETHEUS}"
+            "uid": "prometheus"
           },
           "disableTextWrap": false,
           "editorMode": "builder",
@@ -910,7 +886,7 @@
     {
       "datasource": {
         "type": "prometheus",
-        "uid": "${DS_PROMETHEUS}"
+        "uid": "prometheus"
       },
       "fieldConfig": {
         "defaults": {
@@ -961,7 +937,7 @@
         {
           "datasource": {
             "type": "prometheus",
-            "uid": "${DS_PROMETHEUS}"
+            "uid": "prometheus"
           },
           "editorMode": "builder",
           "expr": "sum by(le) (nfd_worker_feature_discovery_duration_seconds_bucket)",
@@ -977,7 +953,7 @@
     {
       "datasource": {
         "type": "prometheus",
-        "uid": "${DS_PROMETHEUS}"
+        "uid": "prometheus"
       },
       "fieldConfig": {
         "defaults": {
@@ -1028,7 +1004,7 @@
         {
           "datasource": {
             "type": "prometheus",
-            "uid": "${DS_PROMETHEUS}"
+            "uid": "prometheus"
           },
           "editorMode": "builder",
           "expr": "sum by(le) (nfd_master_nodefeaturerule_processing_duration_seconds_bucket)",
@@ -1044,7 +1020,7 @@
     {
       "datasource": {
         "type": "prometheus",
-        "uid": "${DS_PROMETHEUS}"
+        "uid": "prometheus"
       },
       "fieldConfig": {
         "defaults": {
@@ -1122,7 +1098,7 @@
         {
           "datasource": {
             "type": "prometheus",
-            "uid": "${DS_PROMETHEUS}"
+            "uid": "prometheus"
           },
           "editorMode": "builder",
           "expr": "nfd_master_node_labels_rejected_total",
@@ -1137,7 +1113,7 @@
     {
       "datasource": {
         "type": "prometheus",
-        "uid": "${DS_PROMETHEUS}"
+        "uid": "prometheus"
       },
       "fieldConfig": {
         "defaults": {
@@ -1215,7 +1191,7 @@
         {
           "datasource": {
             "type": "prometheus",
-            "uid": "${DS_PROMETHEUS}"
+            "uid": "prometheus"
           },
           "editorMode": "builder",
           "expr": "nfd_master_node_extendedresources_rejected_total",
@@ -1231,7 +1207,7 @@
     {
       "datasource": {
         "type": "prometheus",
-        "uid": "${DS_PROMETHEUS}"
+        "uid": "prometheus"
       },
       "fieldConfig": {
         "defaults": {
@@ -1309,7 +1285,7 @@
         {
           "datasource": {
             "type": "prometheus",
-            "uid": "${DS_PROMETHEUS}"
+            "uid": "prometheus"
           },
           "editorMode": "builder",
           "expr": "nfd_master_node_taints_rejected_total",
diff --git a/go.mod b/go.mod
index 4969bc977..15f604950 100644
--- a/go.mod
+++ b/go.mod
@@ -1,40 +1,40 @@
 module sigs.k8s.io/node-feature-discovery
 
-go 1.24
+go 1.23.0
 
 require (
-	github.com/Masterminds/sprig/v3 v3.3.0
 	github.com/fsnotify/fsnotify v1.8.0
-	github.com/google/go-cmp v0.7.0
+	github.com/google/go-cmp v0.6.0
 	github.com/google/uuid v1.6.0
-	github.com/jaypipes/ghw v0.14.0
-	github.com/jedib0t/go-pretty/v6 v6.6.7
+	github.com/jaypipes/ghw v0.13.0
+	github.com/jedib0t/go-pretty/v6 v6.6.5
 	github.com/k8stopologyawareschedwg/noderesourcetopology-api v0.1.2
 	github.com/k8stopologyawareschedwg/podfingerprint v0.2.2
-	github.com/klauspost/cpuid/v2 v2.2.10
+	github.com/klauspost/cpuid/v2 v2.2.9
 	github.com/onsi/ginkgo/v2 v2.22.2
 	github.com/onsi/gomega v1.36.2
 	github.com/opencontainers/image-spec v1.1.0
-	github.com/opencontainers/runc v1.2.5
-	github.com/prometheus/client_golang v1.21.0
+	github.com/opencontainers/runc v1.2.4
+	github.com/prometheus/client_golang v1.19.1
 	github.com/smartystreets/goconvey v1.8.1
-	github.com/spf13/cobra v1.9.1
+	github.com/spf13/cobra v1.8.1
 	github.com/stretchr/testify v1.10.0
 	github.com/vektra/errors v0.0.0-20140903201135-c64d83aba85a
 	golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
-	golang.org/x/net v0.35.0
-	golang.org/x/time v0.10.0
-	google.golang.org/grpc v1.70.0
-	k8s.io/api v0.32.2
-	k8s.io/apiextensions-apiserver v0.32.2
-	k8s.io/apimachinery v0.32.2
-	k8s.io/client-go v0.32.2
-	k8s.io/component-base v0.32.2
+	golang.org/x/net v0.34.0
+	golang.org/x/time v0.9.0
+	google.golang.org/grpc v1.69.4
+	k8s.io/api v0.32.0
+	k8s.io/apiextensions-apiserver v0.32.0
+	k8s.io/apimachinery v0.32.0
+	k8s.io/client-go v0.32.0
+	k8s.io/code-generator v0.32.0
+	k8s.io/component-base v0.32.0
 	k8s.io/klog/v2 v2.130.1
-	k8s.io/kubectl v0.32.2
-	k8s.io/kubelet v0.32.2
-	k8s.io/kubernetes v1.32.2
-	k8s.io/pod-security-admission v0.32.2
+	k8s.io/kubectl v0.32.0
+	k8s.io/kubelet v0.32.0
+	k8s.io/kubernetes v1.32.0
+	k8s.io/pod-security-admission v0.32.0
 	k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738
 	oras.land/oras-go/v2 v2.5.0
 	sigs.k8s.io/node-feature-discovery/api/nfd v0.0.0-00010101000000-000000000000
@@ -42,11 +42,8 @@ require (
 )
 
 require (
-	cel.dev/expr v0.19.0 // indirect
-	dario.cat/mergo v1.0.1 // indirect
+	cel.dev/expr v0.18.0 // indirect
 	github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab // indirect
-	github.com/Masterminds/goutils v1.1.1 // indirect
-	github.com/Masterminds/semver/v3 v3.3.0 // indirect
 	github.com/Microsoft/go-winio v0.6.2 // indirect
 	github.com/NYTimes/gziphandler v1.1.1 // indirect
 	github.com/OneOfOne/xxhash v1.2.8 // indirect
@@ -63,7 +60,7 @@ require (
 	github.com/containerd/ttrpc v1.2.5 // indirect
 	github.com/coreos/go-semver v0.3.1 // indirect
 	github.com/coreos/go-systemd/v22 v22.5.0 // indirect
-	github.com/cyphar/filepath-securejoin v0.4.1 // indirect
+	github.com/cyphar/filepath-securejoin v0.3.5 // indirect
 	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
 	github.com/distribution/reference v0.6.0 // indirect
 	github.com/docker/go-units v0.5.0 // indirect
@@ -91,21 +88,16 @@ require (
 	github.com/gorilla/websocket v1.5.0 // indirect
 	github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
-	github.com/huandu/xstrings v1.5.0 // indirect
 	github.com/inconshreveable/mousetrap v1.1.0 // indirect
 	github.com/jaypipes/pcidb v1.0.1 // indirect
 	github.com/josharian/intern v1.0.0 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
 	github.com/jtolds/gls v4.20.0+incompatible // indirect
 	github.com/karrick/godirwalk v1.17.0 // indirect
-	github.com/klauspost/compress v1.17.11 // indirect
-	github.com/kylelemons/godebug v1.1.0 // indirect
 	github.com/mailru/easyjson v0.7.7 // indirect
-	github.com/mattn/go-runewidth v0.0.16 // indirect
+	github.com/mattn/go-runewidth v0.0.15 // indirect
 	github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible // indirect
-	github.com/mitchellh/copystructure v1.2.0 // indirect
 	github.com/mitchellh/go-homedir v1.1.0 // indirect
-	github.com/mitchellh/reflectwalk v1.0.2 // indirect
 	github.com/moby/spdystream v0.5.0 // indirect
 	github.com/moby/sys/mountinfo v0.7.2 // indirect
 	github.com/moby/sys/userns v0.1.0 // indirect
@@ -119,15 +111,12 @@ require (
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
 	github.com/prometheus/client_model v0.6.1 // indirect
-	github.com/prometheus/common v0.62.0 // indirect
+	github.com/prometheus/common v0.55.0 // indirect
 	github.com/prometheus/procfs v0.15.1 // indirect
-	github.com/rivo/uniseg v0.4.7 // indirect
-	github.com/samber/lo v1.47.0 // indirect
-	github.com/shopspring/decimal v1.4.0 // indirect
+	github.com/rivo/uniseg v0.2.0 // indirect
 	github.com/sirupsen/logrus v1.9.3 // indirect
 	github.com/smarty/assertions v1.15.1 // indirect
-	github.com/spf13/cast v1.7.0 // indirect
-	github.com/spf13/pflag v1.0.6 // indirect
+	github.com/spf13/pflag v1.0.5 // indirect
 	github.com/stoewer/go-strcase v1.3.0 // indirect
 	github.com/stretchr/objx v0.5.2 // indirect
 	github.com/x448/float16 v0.8.4 // indirect
@@ -136,46 +125,45 @@ require (
 	go.etcd.io/etcd/client/v3 v3.5.16 // indirect
 	go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect
 	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
-	go.opentelemetry.io/otel v1.32.0 // indirect
+	go.opentelemetry.io/otel v1.31.0 // indirect
 	go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
 	go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect
-	go.opentelemetry.io/otel/metric v1.32.0 // indirect
-	go.opentelemetry.io/otel/sdk v1.32.0 // indirect
-	go.opentelemetry.io/otel/trace v1.32.0 // indirect
+	go.opentelemetry.io/otel/metric v1.31.0 // indirect
+	go.opentelemetry.io/otel/sdk v1.31.0 // indirect
+	go.opentelemetry.io/otel/trace v1.31.0 // indirect
 	go.opentelemetry.io/proto/otlp v1.3.1 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
 	go.uber.org/zap v1.27.0 // indirect
-	golang.org/x/crypto v0.33.0 // indirect
+	golang.org/x/crypto v0.32.0 // indirect
 	golang.org/x/mod v0.22.0 // indirect
-	golang.org/x/oauth2 v0.24.0 // indirect
-	golang.org/x/sync v0.11.0 // indirect
-	golang.org/x/sys v0.30.0 // indirect
-	golang.org/x/term v0.29.0 // indirect
-	golang.org/x/text v0.22.0 // indirect
+	golang.org/x/oauth2 v0.23.0 // indirect
+	golang.org/x/sync v0.10.0 // indirect
+	golang.org/x/sys v0.29.0 // indirect
+	golang.org/x/term v0.28.0 // indirect
+	golang.org/x/text v0.21.0 // indirect
 	golang.org/x/tools v0.28.0 // indirect
 	google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
-	google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a // indirect
-	google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect
+	google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect
 	google.golang.org/protobuf v1.36.1 // indirect
 	gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 	howett.net/plist v1.0.0 // indirect
-	k8s.io/apiserver v0.32.2 // indirect
-	k8s.io/cloud-provider v0.32.2 // indirect
-	k8s.io/code-generator v0.32.2 // indirect
-	k8s.io/component-helpers v0.32.2 // indirect
-	k8s.io/controller-manager v0.32.2 // indirect
-	k8s.io/cri-api v0.32.2 // indirect
+	k8s.io/apiserver v0.32.0 // indirect
+	k8s.io/cloud-provider v0.32.0 // indirect
+	k8s.io/component-helpers v0.32.0 // indirect
+	k8s.io/controller-manager v0.32.0 // indirect
+	k8s.io/cri-api v0.32.0 // indirect
 	k8s.io/cri-client v0.0.0 // indirect
-	k8s.io/csi-translation-lib v0.32.2 // indirect
-	k8s.io/dynamic-resource-allocation v0.32.2 // indirect
+	k8s.io/csi-translation-lib v0.32.0 // indirect
+	k8s.io/dynamic-resource-allocation v0.32.0 // indirect
 	k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9 // indirect
-	k8s.io/kms v0.32.2 // indirect
+	k8s.io/kms v0.32.0 // indirect
 	k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect
-	k8s.io/kube-scheduler v0.32.2 // indirect
-	k8s.io/mount-utils v0.32.2 // indirect
+	k8s.io/kube-scheduler v0.0.0 // indirect
+	k8s.io/mount-utils v0.32.0 // indirect
 	sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 // indirect
 	sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
 	sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect
@@ -185,33 +173,31 @@ require (
 // need to override with commits (corresponding their kubernetes-* tags)
 replace (
 	github.com/gogo/protobuf => github.com/gogo/protobuf v1.3.2
-	k8s.io/api => k8s.io/api v0.32.2
-	k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.32.2
-	k8s.io/apimachinery => k8s.io/apimachinery v0.32.2
-	k8s.io/apiserver => k8s.io/apiserver v0.32.2
-	k8s.io/cli-runtime => k8s.io/cli-runtime v0.32.2
-	k8s.io/client-go => k8s.io/client-go v0.32.2
-	k8s.io/cloud-provider => k8s.io/cloud-provider v0.32.2
-	k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.32.2
-	k8s.io/code-generator => k8s.io/code-generator v0.32.2
-	k8s.io/component-base => k8s.io/component-base v0.32.2
-	k8s.io/component-helpers => k8s.io/component-helpers v0.32.2
-	k8s.io/controller-manager => k8s.io/controller-manager v0.32.2
-	k8s.io/cri-api => k8s.io/cri-api v0.32.2
-	k8s.io/cri-client => k8s.io/cri-client v0.32.2
-	k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.32.2
-	k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.32.2
-	k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.32.2
-	k8s.io/kube-proxy => k8s.io/kube-proxy v0.32.2
-	k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.32.2
-	k8s.io/kubectl => k8s.io/kubectl v0.32.2
-	k8s.io/kubelet => k8s.io/kubelet v0.32.2
-	k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.32.2
-	k8s.io/metrics => k8s.io/metrics v0.32.2
-	k8s.io/mount-utils => k8s.io/mount-utils v0.32.2
-	k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.32.2
-	k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.32.2
+	k8s.io/api => k8s.io/api v0.32.0
+	k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.32.0
+	k8s.io/apimachinery => k8s.io/apimachinery v0.32.0
+	k8s.io/apiserver => k8s.io/apiserver v0.32.0
+	k8s.io/cli-runtime => k8s.io/cli-runtime v0.32.0
+	k8s.io/client-go => k8s.io/client-go v0.32.0
+	k8s.io/cloud-provider => k8s.io/cloud-provider v0.32.0
+	k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.32.0
+	k8s.io/code-generator => k8s.io/code-generator v0.32.0
+	k8s.io/component-base => k8s.io/component-base v0.32.0
+	k8s.io/component-helpers => k8s.io/component-helpers v0.32.0
+	k8s.io/controller-manager => k8s.io/controller-manager v0.32.0
+	k8s.io/cri-api => k8s.io/cri-api v0.32.0
+	k8s.io/cri-client => k8s.io/cri-client v0.32.0
+	k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.32.0
+	k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.32.0
+	k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.32.0
+	k8s.io/kube-proxy => k8s.io/kube-proxy v0.32.0
+	k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.32.0
+	k8s.io/kubectl => k8s.io/kubectl v0.32.0
+	k8s.io/kubelet => k8s.io/kubelet v0.32.0
+	k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.32.0
+	k8s.io/metrics => k8s.io/metrics v0.32.0
+	k8s.io/mount-utils => k8s.io/mount-utils v0.32.0
+	k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.32.0
+	k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.32.0
 	sigs.k8s.io/node-feature-discovery/api/nfd => ./api/nfd
 )
-
-tool k8s.io/code-generator
diff --git a/go.sum b/go.sum
index 8dc42a4a9..8c7c856cf 100644
--- a/go.sum
+++ b/go.sum
@@ -1,15 +1,7 @@
-cel.dev/expr v0.19.0 h1:lXuo+nDhpyJSpWxpPVi5cPUwzKb+dsdOiw6IreM5yt0=
-cel.dev/expr v0.19.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
-dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
-dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
+cel.dev/expr v0.18.0 h1:CJ6drgk+Hf96lkLikr4rFf19WrU0BOWEihyZnI2TAzo=
+cel.dev/expr v0.18.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
 github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab h1:UKkYhof1njT1/xq4SEg5z+VpTgjmNeHwPGRQl7takDI=
 github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab/go.mod h1:3VYc5hodBMJ5+l/7J4xAyMeuM2PNuepvHlGs8yilUCA=
-github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
-github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
-github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0=
-github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
-github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs=
-github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=
 github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
 github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
 github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
@@ -46,10 +38,10 @@ github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr
 github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
 github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
 github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
-github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
+github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
-github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
-github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
+github.com/cyphar/filepath-securejoin v0.3.5 h1:L81NHjquoQmcPgXcttUS9qTSR/+bXry6pbSINQGpjj4=
+github.com/cyphar/filepath-securejoin v0.3.5/go.mod h1:edhVd3c6OXKjUmSrVa/tGJRS9joFTxlslFCAyaxigkE=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
@@ -70,8 +62,6 @@ github.com/euank/go-kmsg-parser v2.0.0+incompatible h1:cHD53+PLQuuQyLZeriD1V/esu
 github.com/euank/go-kmsg-parser v2.0.0+incompatible/go.mod h1:MhmAMZ8V4CYH4ybgdRwPr2TU5ThnS43puaKEMpja1uw=
 github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
 github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
-github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
-github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
 github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
 github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
 github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
@@ -114,8 +104,8 @@ github.com/google/cel-go v0.22.0/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs
 github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
 github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
 github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
-github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
 github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@@ -135,16 +125,14 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4
 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
-github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
-github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
 github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
-github.com/jaypipes/ghw v0.14.0 h1:Z2AunEykaBYXLgpntVQB8SGmIFuCEmCcj6aS5j8xrys=
-github.com/jaypipes/ghw v0.14.0/go.mod h1:F4UM7Ix55ONYwD3Lck2S4BI+hKezOwtizuJxXDFsioo=
+github.com/jaypipes/ghw v0.13.0 h1:log8MXuB8hzTNnSktqpXMHc0c/2k/WgjOMSUtnI1RV4=
+github.com/jaypipes/ghw v0.13.0/go.mod h1:In8SsaDqlb1oTyrbmTC14uy+fbBMvp+xdqX51MidlD8=
 github.com/jaypipes/pcidb v1.0.1 h1:WB2zh27T3nwg8AE8ei81sNRb9yWBii3JGNJtT7K9Oic=
 github.com/jaypipes/pcidb v1.0.1/go.mod h1:6xYUz/yYEyOkIkUt2t2J2folIuZ4Yg6uByCGFXMCeE4=
-github.com/jedib0t/go-pretty/v6 v6.6.7 h1:m+LbHpm0aIAPLzLbMfn8dc3Ht8MW7lsSO4MPItz/Uuo=
-github.com/jedib0t/go-pretty/v6 v6.6.7/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU=
+github.com/jedib0t/go-pretty/v6 v6.6.5 h1:9PgMJOVBedpgYLI56jQRJYqngxYAAzfEUua+3NgSqAo=
+github.com/jedib0t/go-pretty/v6 v6.6.5/go.mod h1:Uq/HrbhuFty5WSVNfjpQQe47x16RwVGXIveNGEyGtHs=
 github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
 github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
 github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
@@ -162,10 +150,8 @@ github.com/karrick/godirwalk v1.17.0 h1:b4kY7nqDdioR/6qnbHQyDvmA17u5G1cZ6J+CZXwS
 github.com/karrick/godirwalk v1.17.0/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
 github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
-github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
-github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
-github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
+github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
+github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
 github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
 github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -173,20 +159,14 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
-github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
 github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
-github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
-github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
+github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
 github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible h1:aKW/4cBs+yK6gpqU3K/oIwk9Q/XICqd3zOX/UFuvqmk=
 github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
-github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
-github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
 github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
-github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
 github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
 github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
 github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=
@@ -212,8 +192,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
 github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
 github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
-github.com/opencontainers/runc v1.2.5 h1:8KAkq3Wrem8bApgOHyhRI/8IeLXIfmZ6Qaw6DNSLnA4=
-github.com/opencontainers/runc v1.2.5/go.mod h1:dOQeFo29xZKBNeRBI0B19mJtfHv68YgCTh1X+YphA+4=
+github.com/opencontainers/runc v1.2.4 h1:yWFgLkghp71D76Fa0l349yAl5g4Gse7DPYNlvkQ9Eiw=
+github.com/opencontainers/runc v1.2.4/go.mod h1:nSxcWUydXrsBZVYNSkTjoQ/N6rcyTtn+1SD5D4+kRIM=
 github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk=
 github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
 github.com/opencontainers/selinux v1.11.1 h1:nHFvthhM0qY8/m+vfhJylliSshm8G1jJ2jDMcgULaH8=
@@ -223,24 +203,19 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_golang v1.21.0 h1:DIsaGmiaBkSangBgMtWdNfxbMNdku5IK6iNhrEqWvdA=
-github.com/prometheus/client_golang v1.21.0/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
+github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
+github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
 github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
 github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
-github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
-github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
+github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
+github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
 github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
 github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
+github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
-github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
-github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
 github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
 github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc=
-github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU=
-github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
-github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
 github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
 github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
 github.com/smarty/assertions v1.15.1 h1:812oFiXI+G55vxsFf+8bIZ1ux30qtkdqzKbEFwyX3Tk=
@@ -249,12 +224,10 @@ github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sS
 github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60=
 github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
 github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
-github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
-github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
-github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
-github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
-github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
-github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
+github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
 github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -299,20 +272,20 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.5
 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74=
 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
-go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U=
-go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg=
+go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY=
+go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=
 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY=
 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI=
 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA=
 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ=
-go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M=
-go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8=
-go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4=
-go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU=
-go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU=
-go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ=
-go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM=
-go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
+go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE=
+go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY=
+go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk=
+go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0=
+go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc=
+go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=
+go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys=
+go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A=
 go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
 go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
 go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
@@ -324,8 +297,8 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
-golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
+golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
+golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -336,30 +309,30 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
-golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
-golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
-golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
+golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
+golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
+golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
+golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
-golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
+golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
-golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
-golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
+golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
+golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
+golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
-golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
-golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4=
-golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
+golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
+golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
@@ -372,12 +345,12 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY=
 google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo=
-google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a h1:OAiGFfOiA0v9MRYsSidp3ubZaBnteRUyn3xB2ZQ5G/E=
-google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a/go.mod h1:jehYqy3+AhJU9ve55aNOaSml7wUXjF9x6z2LcCfpAhY=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a h1:hgh8P4EuoxpsuKMXX/To36nOFD7vixReXgn8lPGnt+o=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
-google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ=
-google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw=
+google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 h1:fVoAXEKA4+yufmbdVYv+SE73+cPZbbbe8paLsHfkK+U=
+google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53/go.mod h1:riSXTwQ4+nqmPGtobMFyW5FqVAmIs0St6VPp4Ug7CE4=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
+google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A=
+google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
 google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
 google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -395,54 +368,54 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
 howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
-k8s.io/api v0.32.2 h1:bZrMLEkgizC24G9eViHGOPbW+aRo9duEISRIJKfdJuw=
-k8s.io/api v0.32.2/go.mod h1:hKlhk4x1sJyYnHENsrdCWw31FEmCijNGPJO5WzHiJ6Y=
-k8s.io/apiextensions-apiserver v0.32.2 h1:2YMk285jWMk2188V2AERy5yDwBYrjgWYggscghPCvV4=
-k8s.io/apiextensions-apiserver v0.32.2/go.mod h1:GPwf8sph7YlJT3H6aKUWtd0E+oyShk/YHWQHf/OOgCA=
-k8s.io/apimachinery v0.32.2 h1:yoQBR9ZGkA6Rgmhbp/yuT9/g+4lxtsGYwW6dR6BDPLQ=
-k8s.io/apimachinery v0.32.2/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
-k8s.io/apiserver v0.32.2 h1:WzyxAu4mvLkQxwD9hGa4ZfExo3yZZaYzoYvvVDlM6vw=
-k8s.io/apiserver v0.32.2/go.mod h1:PEwREHiHNU2oFdte7BjzA1ZyjWjuckORLIK/wLV5goM=
-k8s.io/client-go v0.32.2 h1:4dYCD4Nz+9RApM2b/3BtVvBHw54QjMFUl1OLcJG5yOA=
-k8s.io/client-go v0.32.2/go.mod h1:fpZ4oJXclZ3r2nDOv+Ux3XcJutfrwjKTCHz2H3sww94=
-k8s.io/cloud-provider v0.32.2 h1:8EC+fCYo0r0REczSjOZcVuQPCMxXxCKlgxDbYMrzC30=
-k8s.io/cloud-provider v0.32.2/go.mod h1:2s8TeAXhVezp5VISaTxM6vW3yDonOZXoN4Aryz1p1PQ=
-k8s.io/code-generator v0.32.2 h1:CIvyPrLWP7cMgrqval2qYT839YAwCDeSvGfXgWSNpHQ=
-k8s.io/code-generator v0.32.2/go.mod h1:plh7bWk7JztAUkHM4zpbdy0KOMdrhsePcZL2HLWFH7Y=
-k8s.io/component-base v0.32.2 h1:1aUL5Vdmu7qNo4ZsE+569PV5zFatM9hl+lb3dEea2zU=
-k8s.io/component-base v0.32.2/go.mod h1:PXJ61Vx9Lg+P5mS8TLd7bCIr+eMJRQTyXe8KvkrvJq0=
-k8s.io/component-helpers v0.32.2 h1:2usSAm3zNE5yu5DdAdrKBWLfSYNpU4OPjZywJY5ovP8=
-k8s.io/component-helpers v0.32.2/go.mod h1:fvQAoiiOP7jUEUBc9qR0PXiBPuB0I56WTxTkkpcI8g8=
-k8s.io/controller-manager v0.32.2 h1:/9XuHWEqofO2Aqa4l7KJGckJUcLVRWfx+qnVkdXoStI=
-k8s.io/controller-manager v0.32.2/go.mod h1:o5uo2tLCQhuoMt0RfKcQd0eqaNmSKOKiT+0YELCqXOk=
-k8s.io/cri-api v0.32.2 h1:7DuaOHpOcXweZeBUbRdK0iCroxctGp73VwgrA0u7kho=
-k8s.io/cri-api v0.32.2/go.mod h1:DCzMuTh2padoinefWME0G678Mc3QFbLMF2vEweGzBAI=
-k8s.io/cri-client v0.32.2 h1:vjowJUyu14IbmifqCKJHE9rK/BPSfkXvltqN42W1Zuo=
-k8s.io/cri-client v0.32.2/go.mod h1:fRZhmmZW16Qviln8hfy+e8dd2wP/n9B6TiGxLE3zBe0=
-k8s.io/csi-translation-lib v0.32.2 h1:aLzAyaoJUc5rgtLi8Xd4No1tet6UpvUsGIgRoGnPSSE=
-k8s.io/csi-translation-lib v0.32.2/go.mod h1:PlOKan6Vc0G6a+giQbm36plJ+E1LH+GPRLAVMQMSMcY=
-k8s.io/dynamic-resource-allocation v0.32.2 h1:6wP8/GGvhhvTJLrzwPSoMJDnspmosFj1CKmfrAH6m5U=
-k8s.io/dynamic-resource-allocation v0.32.2/go.mod h1:+3qnQfvikLHVZrdZ0/gYkRiV96weUR9j7+Ph3Ui/hYU=
+k8s.io/api v0.32.0 h1:OL9JpbvAU5ny9ga2fb24X8H6xQlVp+aJMFlgtQjR9CE=
+k8s.io/api v0.32.0/go.mod h1:4LEwHZEf6Q/cG96F3dqR965sYOfmPM7rq81BLgsE0p0=
+k8s.io/apiextensions-apiserver v0.32.0 h1:S0Xlqt51qzzqjKPxfgX1xh4HBZE+p8KKBq+k2SWNOE0=
+k8s.io/apiextensions-apiserver v0.32.0/go.mod h1:86hblMvN5yxMvZrZFX2OhIHAuFIMJIZ19bTvzkP+Fmw=
+k8s.io/apimachinery v0.32.0 h1:cFSE7N3rmEEtv4ei5X6DaJPHHX0C+upp+v5lVPiEwpg=
+k8s.io/apimachinery v0.32.0/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
+k8s.io/apiserver v0.32.0 h1:VJ89ZvQZ8p1sLeiWdRJpRD6oLozNZD2+qVSLi+ft5Qs=
+k8s.io/apiserver v0.32.0/go.mod h1:HFh+dM1/BE/Hm4bS4nTXHVfN6Z6tFIZPi649n83b4Ag=
+k8s.io/client-go v0.32.0 h1:DimtMcnN/JIKZcrSrstiwvvZvLjG0aSxy8PxN8IChp8=
+k8s.io/client-go v0.32.0/go.mod h1:boDWvdM1Drk4NJj/VddSLnx59X3OPgwrOo0vGbtq9+8=
+k8s.io/cloud-provider v0.32.0 h1:QXYJGmwME2q2rprymbmw2GroMChQYc/MWN6l/I4Kgp8=
+k8s.io/cloud-provider v0.32.0/go.mod h1:cz3gVodkhgwi2ugj/JUPglIruLSdDaThxawuDyCHfr8=
+k8s.io/code-generator v0.32.0 h1:s0lNN8VSWny8LBz5t5iy7MCdgwdOhdg7vAGVxvS+VWU=
+k8s.io/code-generator v0.32.0/go.mod h1:b7Q7KMZkvsYFy72A79QYjiv4aTz3GvW0f1T3UfhFq4s=
+k8s.io/component-base v0.32.0 h1:d6cWHZkCiiep41ObYQS6IcgzOUQUNpywm39KVYaUqzU=
+k8s.io/component-base v0.32.0/go.mod h1:JLG2W5TUxUu5uDyKiH2R/7NnxJo1HlPoRIIbVLkK5eM=
+k8s.io/component-helpers v0.32.0 h1:pQEEBmRt3pDJJX98cQvZshDgJFeKRM4YtYkMmfOlczw=
+k8s.io/component-helpers v0.32.0/go.mod h1:9RuClQatbClcokXOcDWSzFKQm1huIf0FzQlPRpizlMc=
+k8s.io/controller-manager v0.32.0 h1:tpQl1rvH4huFB6Avl1nhowZHtZoCNWqn6OYdZPl7Ybc=
+k8s.io/controller-manager v0.32.0/go.mod h1:JRuYnYCkKj3NgBTy+KNQKIUm/lJRoDAvGbfdEmk9LhY=
+k8s.io/cri-api v0.32.0 h1:pzXJfyG7Tm4acrEt5HPqAq3r4cN5guLeapAN/NM2b70=
+k8s.io/cri-api v0.32.0/go.mod h1:DCzMuTh2padoinefWME0G678Mc3QFbLMF2vEweGzBAI=
+k8s.io/cri-client v0.32.0 h1:K6aTYDyS2AS8O4h79eI5r26562xstdybprtaaszjn+E=
+k8s.io/cri-client v0.32.0/go.mod h1:FB8qZNj8KrwIFfVIR2zBGb+l6KUhrp+k8YFsVp3D+kw=
+k8s.io/csi-translation-lib v0.32.0 h1:RAn9RGgYXHJQtDSb6qQ7zvq6QObOejzmsXDARI+f4OQ=
+k8s.io/csi-translation-lib v0.32.0/go.mod h1:TjCJzkTNstdOESAXNnEImrYOMIEzP14aqM7H+vkehqw=
+k8s.io/dynamic-resource-allocation v0.32.0 h1:0ZLSCKzlLZLVwKHxg6vafpd2U8b7jPMO3k8bbMFodis=
+k8s.io/dynamic-resource-allocation v0.32.0/go.mod h1:MfoAUi0vCJtchNirAVk7c3IYfGGB3n+zbZ9GuyX4eeo=
 k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9 h1:si3PfKm8dDYxgfbeA6orqrtLkvvIeH8UqffFJDl0bz4=
 k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU=
 k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
 k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
-k8s.io/kms v0.32.2 h1:7Ff23ht7W40gTcDwUC8G5WjX5W/nxD8WxbNhIYYNZCI=
-k8s.io/kms v0.32.2/go.mod h1:Bk2evz/Yvk0oVrvm4MvZbgq8BD34Ksxs2SRHn4/UiOM=
+k8s.io/kms v0.32.0 h1:jwOfunHIrcdYl5FRcA+uUKKtg6qiqoPCwmS2T3XTYL4=
+k8s.io/kms v0.32.0/go.mod h1:Bk2evz/Yvk0oVrvm4MvZbgq8BD34Ksxs2SRHn4/UiOM=
 k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y=
 k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4=
-k8s.io/kube-scheduler v0.32.2 h1:vBm6iIjWaD10OPmtkt/503LTKvrN8dWVceeBcpKj/ns=
-k8s.io/kube-scheduler v0.32.2/go.mod h1:dD5yuYpnsCfgZmzvncUNPdvXGJXA1hw3gXq7DH3+aCQ=
-k8s.io/kubectl v0.32.2 h1:TAkag6+XfSBgkqK9I7ZvwtF0WVtUAvK8ZqTt+5zi1Us=
-k8s.io/kubectl v0.32.2/go.mod h1:+h/NQFSPxiDZYX/WZaWw9fwYezGLISP0ud8nQKg+3g8=
-k8s.io/kubelet v0.32.2 h1:WFTSYdt3BB1aTApDuKNI16x/4MYqqX8WBBBBh3KupDg=
-k8s.io/kubelet v0.32.2/go.mod h1:cC1ms5RS+lu0ckVr6AviCQXHLSPKEBC3D5oaCBdTGkI=
-k8s.io/kubernetes v1.32.2 h1:mShetlA102UpjRVSGzB+5vjJwy8oPy8FMWrkTH5f37o=
-k8s.io/kubernetes v1.32.2/go.mod h1:tiIKO63GcdPRBHW2WiUFm3C0eoLczl3f7qi56Dm1W8I=
-k8s.io/mount-utils v0.32.2 h1:aDwp+ucWiVnDr/LpRg88/dsXf/vm6gI1VZkYH3+3+Vw=
-k8s.io/mount-utils v0.32.2/go.mod h1:Kun5c2svjAPx0nnvJKYQWhfeNW+O0EpzHgRhDcYoSY0=
-k8s.io/pod-security-admission v0.32.2 h1:zDfAb/t0LbNU3z0ZMHtCb1zp8x05gWCGhmBYpUptm9A=
-k8s.io/pod-security-admission v0.32.2/go.mod h1:yxMPB3i1pGMLfxbe4BiWMuowMD7cdHR32y4nCj4wH+s=
+k8s.io/kube-scheduler v0.32.0 h1:FCsF/3TPvR51ptx/gLUrqcoKqAMhQKrydYCJzPz9VGM=
+k8s.io/kube-scheduler v0.32.0/go.mod h1:yof3vmyx70TWoQ6XZruYEGIUT/r0H/ELGdnWiqPF5EE=
+k8s.io/kubectl v0.32.0 h1:rpxl+ng9qeG79YA4Em9tLSfX0G8W0vfaiPVrc/WR7Xw=
+k8s.io/kubectl v0.32.0/go.mod h1:qIjSX+QgPQUgdy8ps6eKsYNF+YmFOAO3WygfucIqFiE=
+k8s.io/kubelet v0.32.0 h1:uLyiKlz195Wo4an/K2tyge8o3QHx0ZkhVN3pevvp59A=
+k8s.io/kubelet v0.32.0/go.mod h1:lAwuVZT/Hm7EdLn0jW2D+WdrJoorjJL2rVSdhOFnegw=
+k8s.io/kubernetes v1.32.0 h1:4BDBWSolqPrv8GC3YfZw0CJvh5kA1TPnoX0FxDVd+qc=
+k8s.io/kubernetes v1.32.0/go.mod h1:tiIKO63GcdPRBHW2WiUFm3C0eoLczl3f7qi56Dm1W8I=
+k8s.io/mount-utils v0.32.0 h1:KOQAhPzJICATXnc6XCkWoexKbkOexRnMCUW8APFfwg4=
+k8s.io/mount-utils v0.32.0/go.mod h1:Kun5c2svjAPx0nnvJKYQWhfeNW+O0EpzHgRhDcYoSY0=
+k8s.io/pod-security-admission v0.32.0 h1:I+Og0uZIiMpIgTgPrTbW4jlwRI5RWazi8y+jrx1v10w=
+k8s.io/pod-security-admission v0.32.0/go.mod h1:RvrcY0+5UAoCIJ7BscgDF3nbmXprgfnjTW+byCyXDvA=
 k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=
 k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
 oras.land/oras-go/v2 v2.5.0 h1:o8Me9kLY74Vp5uw07QXPiitjsw7qNXi8Twd+19Zf02c=
diff --git a/hack/tools.go b/hack/tools.go
new file mode 100644
index 000000000..e38e6c643
--- /dev/null
+++ b/hack/tools.go
@@ -0,0 +1,20 @@
+/*
+Copyright 2024 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// This package imports things required by build scripts, to force `go mod` to see them as dependencies
+package tools
+
+import _ "k8s.io/code-generator"
diff --git a/pkg/apis/nfd/nodefeaturerule/rule.go b/pkg/apis/nfd/nodefeaturerule/rule.go
index fffb6ca16..9289eaa12 100644
--- a/pkg/apis/nfd/nodefeaturerule/rule.go
+++ b/pkg/apis/nfd/nodefeaturerule/rule.go
@@ -17,16 +17,17 @@ limitations under the License.
 package nodefeaturerule
 
 import (
+	"bytes"
 	"fmt"
 	"maps"
 	"slices"
 	"strings"
+	"text/template"
 
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/klog/v2"
 
 	nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1"
-	"sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/template"
 	"sigs.k8s.io/node-feature-discovery/pkg/utils"
 )
 
@@ -187,12 +188,12 @@ func executeLabelsTemplate(r *nfdv1alpha1.Rule, in matchedFeatures, out map[stri
 		return nil
 	}
 
-	th, err := template.NewHelper(r.LabelsTemplate)
+	th, err := newTemplateHelper(r.LabelsTemplate)
 	if err != nil {
 		return fmt.Errorf("failed to parse LabelsTemplate: %w", err)
 	}
 
-	labels, err := th.ExpandMap(in)
+	labels, err := th.expandMap(in)
 	if err != nil {
 		return fmt.Errorf("failed to expand LabelsTemplate: %w", err)
 	}
@@ -207,12 +208,12 @@ func executeVarsTemplate(r *nfdv1alpha1.Rule, in matchedFeatures, out map[string
 		return nil
 	}
 
-	th, err := template.NewHelper(r.VarsTemplate)
+	th, err := newTemplateHelper(r.VarsTemplate)
 	if err != nil {
 		return err
 	}
 
-	vars, err := th.ExpandMap(in)
+	vars, err := th.expandMap(in)
 	if err != nil {
 		return err
 	}
@@ -308,3 +309,47 @@ func evaluateFeatureMatcher(m *nfdv1alpha1.FeatureMatcher, features *nfdv1alpha1
 	}
 	return isMatch, status, nil
 }
+
+type templateHelper struct {
+	template *template.Template
+}
+
+func newTemplateHelper(name string) (*templateHelper, error) {
+	tmpl, err := template.New("").Option("missingkey=error").Parse(name)
+	if err != nil {
+		return nil, fmt.Errorf("invalid template: %w", err)
+	}
+	return &templateHelper{template: tmpl}, nil
+}
+
+func (h *templateHelper) execute(data interface{}) (string, error) {
+	var tmp bytes.Buffer
+	if err := h.template.Execute(&tmp, data); err != nil {
+		return "", err
+	}
+	return tmp.String(), nil
+}
+
+// expandMap is a helper for expanding a template in to a map of strings. Data
+// after executing the template is expexted to be key=value pairs separated by
+// newlines.
+func (h *templateHelper) expandMap(data interface{}) (map[string]string, error) {
+	expanded, err := h.execute(data)
+	if err != nil {
+		return nil, err
+	}
+
+	// Split out individual key-value pairs
+	out := make(map[string]string)
+	for _, item := range strings.Split(expanded, "\n") {
+		// Remove leading/trailing whitespace and skip empty lines
+		if trimmed := strings.TrimSpace(item); trimmed != "" {
+			split := strings.SplitN(trimmed, "=", 2)
+			if len(split) == 1 {
+				return nil, fmt.Errorf("missing value in expanded template line %q, (format must be '<key>=<value>')", trimmed)
+			}
+			out[split[0]] = split[1]
+		}
+	}
+	return out, nil
+}
diff --git a/pkg/apis/nfd/template/template.go b/pkg/apis/nfd/template/template.go
deleted file mode 100644
index 4c0242495..000000000
--- a/pkg/apis/nfd/template/template.go
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
-Copyright 2025 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package template
-
-import (
-	"bytes"
-	"fmt"
-	"strings"
-	"text/template"
-
-	"github.com/Masterminds/sprig/v3"
-)
-
-type Helper struct {
-	template *template.Template
-}
-
-func NewHelper(name string) (*Helper, error) {
-	tmpl := template.New("").Funcs(sprig.FuncMap()).Option("missingkey=error")
-	tmpl, err := tmpl.Parse(name)
-	if err != nil {
-		return nil, fmt.Errorf("invalid template: %w", err)
-	}
-	return &Helper{template: tmpl}, nil
-}
-
-func (h *Helper) execute(data interface{}) (string, error) {
-	var tmp bytes.Buffer
-	if err := h.template.Execute(&tmp, data); err != nil {
-		return "", err
-	}
-	return tmp.String(), nil
-}
-
-// ExpandMap is a helper for expanding a template in to a map of strings. Data
-// after executing the template is expected to be key=value pairs separated by
-// newlines.
-func (h *Helper) ExpandMap(data interface{}) (map[string]string, error) {
-	expanded, err := h.execute(data)
-	if err != nil {
-		return nil, err
-	}
-
-	// Split out individual key-value pairs
-	out := make(map[string]string)
-	for _, item := range strings.Split(expanded, "\n") {
-		// Remove leading/trailing whitespace and skip empty lines
-		if trimmed := strings.TrimSpace(item); trimmed != "" {
-			split := strings.SplitN(trimmed, "=", 2)
-			if len(split) == 1 {
-				return nil, fmt.Errorf("missing value in expanded template line %q, (format must be '<key>=<value>')", trimmed)
-			}
-			out[split[0]] = split[1]
-		}
-	}
-	return out, nil
-}
diff --git a/pkg/apis/nfd/validate/validate.go b/pkg/apis/nfd/validate/validate.go
index 56dc0e1e1..daa65bb02 100644
--- a/pkg/apis/nfd/validate/validate.go
+++ b/pkg/apis/nfd/validate/validate.go
@@ -19,13 +19,13 @@ package validate
 import (
 	"fmt"
 	"strings"
+	"text/template"
 
 	corev1 "k8s.io/api/core/v1"
 	k8sQuantity "k8s.io/apimachinery/pkg/api/resource"
 	k8svalidation "k8s.io/apimachinery/pkg/util/validation"
 
 	nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1"
-	"sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/template"
 )
 
 var (
@@ -70,10 +70,11 @@ func MatchFeatures(matchFeature nfdv1alpha1.FeatureMatcher) []error {
 // template is invalid.
 func Template(labelsTemplate string) []error {
 	var validationErr []error
-	// Only validate template
-	_, err := template.NewHelper(labelsTemplate)
+
+	// Validate template
+	_, err := template.New("").Option("missingkey=error").Parse(labelsTemplate)
 	if err != nil {
-		validationErr = append(validationErr, err)
+		validationErr = append(validationErr, fmt.Errorf("invalid template: %w", err))
 	}
 	return validationErr
 }
diff --git a/pkg/client-nfd/compat/artifact-client/mock_ArtifactClient.go b/pkg/client-nfd/compat/artifact-client/mock_ArtifactClient.go
index ec8610617..3c246ee52 100644
--- a/pkg/client-nfd/compat/artifact-client/mock_ArtifactClient.go
+++ b/pkg/client-nfd/compat/artifact-client/mock_ArtifactClient.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.52.2. DO NOT EDIT.
+// Code generated by mockery v2.42.0. DO NOT EDIT.
 
 package compat
 
diff --git a/pkg/nfd-master/nfd-master.go b/pkg/nfd-master/nfd-master.go
index 3dd984724..990ef380b 100644
--- a/pkg/nfd-master/nfd-master.go
+++ b/pkg/nfd-master/nfd-master.go
@@ -20,7 +20,7 @@ import (
 	"encoding/json"
 	"fmt"
 	"maps"
-	"net/http"
+	"net"
 	"os"
 	"path"
 	"path/filepath"
@@ -31,9 +31,10 @@ import (
 	"time"
 
 	"github.com/google/uuid"
-	"github.com/prometheus/client_golang/prometheus"
-	"github.com/prometheus/client_golang/prometheus/promhttp"
 	"golang.org/x/net/context"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/health"
+	"google.golang.org/grpc/health/grpc_health_v1"
 	corev1 "k8s.io/api/core/v1"
 	apiequality "k8s.io/apimachinery/pkg/api/equality"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -114,14 +115,18 @@ type ConfigOverrideArgs struct {
 
 // Args holds command line arguments
 type Args struct {
-	ConfigFile           string
-	Instance             string
-	Klog                 map[string]*utils.KlogFlagVal
-	Kubeconfig           string
-	Port                 int
+	ConfigFile string
+	Instance   string
+	Klog       map[string]*utils.KlogFlagVal
+	Kubeconfig string
+	Port       int
+	// GrpcHealthPort is only needed to avoid races between tests (by skipping the health server).
+	// Could be removed when gRPC labler service is dropped (when nfd-worker tests stop running nfd-master).
+	GrpcHealthPort       int
 	Prune                bool
 	Options              string
 	EnableLeaderElection bool
+	MetricsPort          int
 
 	Overrides ConfigOverrideArgs
 }
@@ -134,6 +139,7 @@ type deniedNs struct {
 type NfdMaster interface {
 	Run() error
 	Stop()
+	WaitForReady(time.Duration) bool
 }
 
 type nfdMaster struct {
@@ -143,7 +149,10 @@ type nfdMaster struct {
 	namespace      string
 	nodeName       string
 	configFilePath string
+	server         *grpc.Server
+	healthServer   *grpc.Server
 	stop           chan struct{}
+	ready          chan struct{}
 	kubeconfig     *restclient.Config
 	k8sClient      k8sclient.Interface
 	nfdClient      nfdclientset.Interface
@@ -157,6 +166,7 @@ func NewNfdMaster(opts ...NfdMasterOption) (NfdMaster, error) {
 	nfd := &nfdMaster{
 		nodeName:  utils.NodeName(),
 		namespace: utils.GetKubernetesNamespace(),
+		ready:     make(chan struct{}),
 		stop:      make(chan struct{}),
 	}
 
@@ -288,22 +298,22 @@ func (m *nfdMaster) Run() error {
 		}
 	}
 
-	httpMux := http.NewServeMux()
-
 	// Register to metrics server
-	promRegistry := prometheus.NewRegistry()
-	promRegistry.MustRegister(
-		buildInfo,
-		nodeUpdateRequests,
-		nodeUpdates,
-		nodeUpdateFailures,
-		nodeLabelsRejected,
-		nodeERsRejected,
-		nodeTaintsRejected,
-		nfrProcessingTime,
-		nfrProcessingErrors)
-	httpMux.Handle("/metrics", promhttp.HandlerFor(promRegistry, promhttp.HandlerOpts{}))
-	registerVersion(version.Get())
+	if m.args.MetricsPort > 0 {
+		m := utils.CreateMetricsServer(m.args.MetricsPort,
+			buildInfo,
+			nodeUpdateRequests,
+			nodeUpdates,
+			nodeUpdateFailures,
+			nodeLabelsRejected,
+			nodeERsRejected,
+			nodeTaintsRejected,
+			nfrProcessingTime,
+			nfrProcessingErrors)
+		go m.Run()
+		registerVersion(version.Get())
+		defer m.Stop()
+	}
 
 	// Run updater that handles events from the nfd CRD API.
 	if m.nfdController != nil {
@@ -314,29 +324,60 @@ func (m *nfdMaster) Run() error {
 		}
 	}
 
-	// Register health probe (at this point we're "ready and live")
-	httpMux.HandleFunc("/healthz", m.Healthz)
+	// Start gRPC server for liveness probe (at this point we're "live")
+	grpcErr := make(chan error)
+	if m.args.GrpcHealthPort != 0 {
+		if err := m.startGrpcHealthServer(grpcErr); err != nil {
+			return fmt.Errorf("failed to start gRPC health server: %w", err)
+		}
+	}
 
-	// Start HTTP server
-	httpServer := http.Server{Addr: fmt.Sprintf(":%d", m.args.Port), Handler: httpMux}
-	go func() {
-		klog.InfoS("http server starting", "port", httpServer.Addr)
-		klog.InfoS("http server stopped", "exitCode", httpServer.ListenAndServe())
-	}()
-	defer httpServer.Close()
+	// Notify that we're ready to accept connections
+	close(m.ready)
 
-	<-m.stop
-	klog.InfoS("shutting down nfd-master")
-	return nil
+	// NFD-Master main event loop
+	for {
+		select {
+		case err := <-grpcErr:
+			return fmt.Errorf("error in serving gRPC: %w", err)
+
+		case <-m.stop:
+			klog.InfoS("shutting down nfd-master")
+			return nil
+		}
+	}
 }
 
-func (m *nfdMaster) Healthz(writer http.ResponseWriter, _ *http.Request) {
-	writer.WriteHeader(http.StatusOK)
+// startGrpcHealthServer starts a gRPC health server for Kubernetes readiness/liveness probes.
+// TODO: improve status checking e.g. with watchdog in the main event loop and
+// cheking that node updater pool is alive.
+func (m *nfdMaster) startGrpcHealthServer(errChan chan<- error) error {
+	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", m.args.GrpcHealthPort))
+	if err != nil {
+		return fmt.Errorf("failed to listen: %w", err)
+	}
+
+	s := grpc.NewServer()
+	grpc_health_v1.RegisterHealthServer(s, health.NewServer())
+	klog.InfoS("gRPC health server serving", "port", m.args.GrpcHealthPort)
+
+	go func() {
+		defer func() {
+			lis.Close()
+		}()
+		if err := s.Serve(lis); err != nil {
+			errChan <- fmt.Errorf("gRPC health server exited with an error: %w", err)
+		}
+		klog.InfoS("gRPC health server stopped")
+	}()
+	m.healthServer = s
+	return nil
 }
 
 // nfdAPIUpdateHandler handles events from the nfd API controller.
 func (m *nfdMaster) nfdAPIUpdateHandler() {
-	// We want to unconditionally update all nodes at startup
+	// We want to unconditionally update all nodes at startup if gRPC is
+	// disabled (i.e. NodeFeature API is enabled)
 	updateAll := true
 	updateNodes := make(map[string]struct{})
 	nodeFeatureGroup := make(map[string]struct{})
@@ -390,6 +431,13 @@ func (m *nfdMaster) nfdAPIUpdateHandler() {
 
 // Stop NfdMaster
 func (m *nfdMaster) Stop() {
+	if m.server != nil {
+		m.server.GracefulStop()
+	}
+	if m.healthServer != nil {
+		m.healthServer.GracefulStop()
+	}
+
 	if m.nfdController != nil {
 		m.nfdController.stop()
 	}
@@ -399,6 +447,16 @@ func (m *nfdMaster) Stop() {
 	close(m.stop)
 }
 
+// Wait until NfdMaster is able able to accept connections.
+func (m *nfdMaster) WaitForReady(timeout time.Duration) bool {
+	select {
+	case <-m.ready:
+		return true
+	case <-time.After(timeout):
+	}
+	return false
+}
+
 // Prune erases all NFD related properties from the node objects of the cluster.
 func (m *nfdMaster) prune() error {
 	if m.config.NoPublish {
diff --git a/pkg/nfd-topology-updater/nfd-topology-updater.go b/pkg/nfd-topology-updater/nfd-topology-updater.go
index d99bc61bd..e65edbea2 100644
--- a/pkg/nfd-topology-updater/nfd-topology-updater.go
+++ b/pkg/nfd-topology-updater/nfd-topology-updater.go
@@ -18,13 +18,16 @@ package nfdtopologyupdater
 
 import (
 	"fmt"
-	"net/http"
+	"net"
 	"net/url"
 	"os"
 	"path/filepath"
 
 	"golang.org/x/net/context"
 
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/health"
+	"google.golang.org/grpc/health/grpc_health_v1"
 	"k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/types"
@@ -34,7 +37,6 @@ import (
 
 	"github.com/k8stopologyawareschedwg/noderesourcetopology-api/pkg/apis/topology/v1alpha2"
 	topologyclientset "github.com/k8stopologyawareschedwg/noderesourcetopology-api/pkg/generated/clientset/versioned"
-	"github.com/prometheus/client_golang/prometheus"
 	"sigs.k8s.io/node-feature-discovery/pkg/nfd-topology-updater/kubeletnotifier"
 	"sigs.k8s.io/node-feature-discovery/pkg/podres"
 	"sigs.k8s.io/node-feature-discovery/pkg/resourcemonitor"
@@ -54,12 +56,13 @@ const (
 
 // Args are the command line arguments
 type Args struct {
-	Port            int
+	MetricsPort     int
 	NoPublish       bool
 	Oneshot         bool
 	KubeConfigFile  string
 	ConfigFile      string
 	KubeletStateDir string
+	GrpcHealthPort  int
 
 	Klog map[string]*utils.KlogFlagVal
 }
@@ -87,6 +90,7 @@ type nfdTopologyUpdater struct {
 	ownerRefs           []metav1.OwnerReference
 	k8sClient           k8sclient.Interface
 	kubeletConfigFunc   func() (*kubeletconfigv1beta1.KubeletConfiguration, error)
+	healthServer        *grpc.Server
 }
 
 // NewTopologyUpdater creates a new NfdTopologyUpdater instance.
@@ -130,8 +134,27 @@ func (w *nfdTopologyUpdater) detectTopologyPolicyAndScope() (string, string, err
 	return klConfig.TopologyManagerPolicy, klConfig.TopologyManagerScope, nil
 }
 
-func (w *nfdTopologyUpdater) Healthz(writer http.ResponseWriter, _ *http.Request) {
-	writer.WriteHeader(http.StatusOK)
+func (w *nfdTopologyUpdater) startGrpcHealthServer(errChan chan<- error) error {
+	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", w.args.GrpcHealthPort))
+	if err != nil {
+		return fmt.Errorf("failed to listen: %w", err)
+	}
+
+	s := grpc.NewServer()
+	grpc_health_v1.RegisterHealthServer(s, health.NewServer())
+	klog.InfoS("gRPC health server serving", "port", w.args.GrpcHealthPort)
+
+	go func() {
+		defer func() {
+			lis.Close()
+		}()
+		if err := s.Serve(lis); err != nil {
+			errChan <- fmt.Errorf("gRPC health server exited with an error: %w", err)
+		}
+		klog.InfoS("gRPC health server stopped")
+	}()
+	w.healthServer = s
+	return nil
 }
 
 // Run nfdTopologyUpdater. Returns if a fatal error is encountered, or, after
@@ -164,14 +187,15 @@ func (w *nfdTopologyUpdater) Run() error {
 		return fmt.Errorf("faild to configure Node Feature Discovery Topology Updater: %w", err)
 	}
 
-	httpMux := http.NewServeMux()
-
 	// Register to metrics server
-	promRegistry := prometheus.NewRegistry()
-	promRegistry.MustRegister(
-		buildInfo,
-		scanErrors)
-	registerVersion(version.Get())
+	if w.args.MetricsPort > 0 {
+		m := utils.CreateMetricsServer(w.args.MetricsPort,
+			buildInfo,
+			scanErrors)
+		go m.Run()
+		registerVersion(version.Get())
+		defer m.Stop()
+	}
 
 	var resScan resourcemonitor.ResourcesScanner
 
@@ -191,19 +215,20 @@ func (w *nfdTopologyUpdater) Run() error {
 		return fmt.Errorf("failed to obtain node resource information: %w", err)
 	}
 
-	// Register health probe (at this point we're "ready and live")
-	httpMux.HandleFunc("/healthz", w.Healthz)
+	grpcErr := make(chan error)
 
-	// Start HTTP server
-	httpServer := http.Server{Addr: fmt.Sprintf(":%d", w.args.Port), Handler: httpMux}
-	go func() {
-		klog.InfoS("http server starting", "port", httpServer.Addr)
-		klog.InfoS("http server stopped", "exitCode", httpServer.ListenAndServe())
-	}()
-	defer httpServer.Close()
+	// Start gRPC server for liveness probe (at this point we're "live")
+	if w.args.GrpcHealthPort != 0 {
+		if err := w.startGrpcHealthServer(grpcErr); err != nil {
+			return fmt.Errorf("failed to start gRPC health server: %w", err)
+		}
+	}
 
 	for {
 		select {
+		case err := <-grpcErr:
+			return fmt.Errorf("error in serving gRPC: %w", err)
+
 		case info := <-w.eventSource:
 			klog.V(4).InfoS("event received, scanning...", "event", info.Event)
 			scanResponse, err := resScan.Scan()
@@ -232,6 +257,9 @@ func (w *nfdTopologyUpdater) Run() error {
 
 		case <-w.stop:
 			klog.InfoS("shutting down nfd-topology-updater")
+			if w.healthServer != nil {
+				w.healthServer.GracefulStop()
+			}
 			return nil
 		}
 	}
diff --git a/pkg/nfd-worker/nfd-worker.go b/pkg/nfd-worker/nfd-worker.go
index 8021cc46e..e709c6d6e 100644
--- a/pkg/nfd-worker/nfd-worker.go
+++ b/pkg/nfd-worker/nfd-worker.go
@@ -19,7 +19,7 @@ package nfdworker
 import (
 	"encoding/json"
 	"fmt"
-	"net/http"
+	"net"
 	"os"
 	"path/filepath"
 	"regexp"
@@ -27,10 +27,11 @@ import (
 	"strings"
 	"time"
 
-	"github.com/prometheus/client_golang/prometheus"
-	"github.com/prometheus/client_golang/prometheus/promhttp"
 	"golang.org/x/exp/maps"
 	"golang.org/x/net/context"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/health"
+	"google.golang.org/grpc/health/grpc_health_v1"
 	"k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/apimachinery/pkg/util/validation"
@@ -92,13 +93,14 @@ type Labels map[string]string
 
 // Args are the command line arguments of NfdWorker.
 type Args struct {
-	ConfigFile  string
-	Klog        map[string]*utils.KlogFlagVal
-	Kubeconfig  string
-	Oneshot     bool
-	Options     string
-	Port        int
-	NoOwnerRefs bool
+	ConfigFile     string
+	Klog           map[string]*utils.KlogFlagVal
+	Kubeconfig     string
+	Oneshot        bool
+	Options        string
+	MetricsPort    int
+	GrpcHealthPort int
+	NoOwnerRefs    bool
 
 	Overrides ConfigOverrideArgs
 }
@@ -116,6 +118,7 @@ type nfdWorker struct {
 	configFilePath      string
 	config              *NFDConfig
 	kubernetesNamespace string
+	healthServer        *grpc.Server
 	k8sClient           k8sclient.Interface
 	nfdClient           nfdclient.Interface
 	stop                chan struct{} // channel for signaling stop
@@ -203,10 +206,6 @@ func newDefaultConfig() *NFDConfig {
 	}
 }
 
-func (w *nfdWorker) Healthz(writer http.ResponseWriter, _ *http.Request) {
-	writer.WriteHeader(http.StatusOK)
-}
-
 func (i *infiniteTicker) Reset(d time.Duration) {
 	switch {
 	case d > 0:
@@ -218,6 +217,29 @@ func (i *infiniteTicker) Reset(d time.Duration) {
 	}
 }
 
+func (w *nfdWorker) startGrpcHealthServer(errChan chan<- error) error {
+	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", w.args.GrpcHealthPort))
+	if err != nil {
+		return fmt.Errorf("failed to listen: %w", err)
+	}
+
+	s := grpc.NewServer()
+	grpc_health_v1.RegisterHealthServer(s, health.NewServer())
+	klog.InfoS("gRPC health server serving", "port", w.args.GrpcHealthPort)
+
+	go func() {
+		defer func() {
+			lis.Close()
+		}()
+		if err := s.Serve(lis); err != nil {
+			errChan <- fmt.Errorf("gRPC health server exited with an error: %w", err)
+		}
+		klog.InfoS("gRPC health server stopped")
+	}()
+	w.healthServer = s
+	return nil
+}
+
 // Run feature discovery.
 func (w *nfdWorker) runFeatureDiscovery() error {
 	discoveryStart := time.Now()
@@ -302,13 +324,15 @@ func (w *nfdWorker) Run() error {
 	labelTrigger.Reset(w.config.Core.SleepInterval.Duration)
 	defer labelTrigger.Stop()
 
-	httpMux := http.NewServeMux()
-
 	// Register to metrics server
-	promRegistry := prometheus.NewRegistry()
-	promRegistry.MustRegister(buildInfo, featureDiscoveryDuration)
-	httpMux.Handle("/metrics", promhttp.HandlerFor(promRegistry, promhttp.HandlerOpts{}))
-	registerVersion(version.Get())
+	if w.args.MetricsPort > 0 {
+		m := utils.CreateMetricsServer(w.args.MetricsPort,
+			buildInfo,
+			featureDiscoveryDuration)
+		go m.Run()
+		registerVersion(version.Get())
+		defer m.Stop()
+	}
 
 	err = w.runFeatureDiscovery()
 	if err != nil {
@@ -320,19 +344,20 @@ func (w *nfdWorker) Run() error {
 		return nil
 	}
 
-	// Register health endpoint (at this point we're "ready and live")
-	httpMux.HandleFunc("/healthz", w.Healthz)
+	grpcErr := make(chan error)
 
-	// Start HTTP server
-	httpServer := http.Server{Addr: fmt.Sprintf(":%d", w.args.Port), Handler: httpMux}
-	go func() {
-		klog.InfoS("http server starting", "port", httpServer.Addr)
-		klog.InfoS("http server stopped", "exitCode", httpServer.ListenAndServe())
-	}()
-	defer httpServer.Close()
+	// Start gRPC server for liveness probe (at this point we're "live")
+	if w.args.GrpcHealthPort != 0 {
+		if err := w.startGrpcHealthServer(grpcErr); err != nil {
+			return fmt.Errorf("failed to start gRPC health server: %w", err)
+		}
+	}
 
 	for {
 		select {
+		case err := <-grpcErr:
+			return fmt.Errorf("error in serving gRPC: %w", err)
+
 		case <-labelTrigger.C:
 			err = w.runFeatureDiscovery()
 			if err != nil {
@@ -341,6 +366,9 @@ func (w *nfdWorker) Run() error {
 
 		case <-w.stop:
 			klog.InfoS("shutting down nfd-worker")
+			if w.healthServer != nil {
+				w.healthServer.GracefulStop()
+			}
 			return nil
 		}
 	}
diff --git a/pkg/podres/mocks/PodResourcesListerClient.go b/pkg/podres/mocks/PodResourcesListerClient.go
index 4e0543b59..33f206205 100644
--- a/pkg/podres/mocks/PodResourcesListerClient.go
+++ b/pkg/podres/mocks/PodResourcesListerClient.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.52.2. DO NOT EDIT.
+// Code generated by mockery v2.42.0. DO NOT EDIT.
 
 package mocks
 
diff --git a/pkg/utils/jsonpatch.go b/pkg/utils/jsonpatch.go
index 92bd5aa1b..bd89302ba 100644
--- a/pkg/utils/jsonpatch.go
+++ b/pkg/utils/jsonpatch.go
@@ -21,11 +21,6 @@ import (
 	"strings"
 )
 
-const (
-	JSONAddOperation    = "add"
-	JSONRemoveOperation = "remove"
-)
-
 // JsonPatch is a json marshaling helper used for patching API objects
 type JsonPatch struct {
 	Op    string `json:"op"`
diff --git a/source/cpu/pstate_amd64.go b/source/cpu/pstate_amd64.go
index ce9dbd662..fab4afe48 100644
--- a/source/cpu/pstate_amd64.go
+++ b/source/cpu/pstate_amd64.go
@@ -72,11 +72,7 @@ func detectPstate() (map[string]string, error) {
 	cpufreqDir := filepath.Join(sysfsBase, "cpufreq")
 	policies, err := os.ReadDir(cpufreqDir)
 	if err != nil {
-		if os.IsNotExist(err) {
-			klog.V(2).InfoS("cpufreq driver not enabled")
-		} else {
-			klog.ErrorS(err, "failed to read cpufreq directory")
-		}
+		klog.ErrorS(err, "failed to read cpufreq directory")
 		return features, nil
 	}
 
diff --git a/source/memory/memory.go b/source/memory/memory.go
index ab9bc02ed..df6bbb76f 100644
--- a/source/memory/memory.go
+++ b/source/memory/memory.go
@@ -17,12 +17,15 @@ limitations under the License.
 package memory
 
 import (
+	"errors"
 	"fmt"
 	"os"
 	"path/filepath"
 	"strconv"
 	"strings"
 
+	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/api/resource"
 	"k8s.io/klog/v2"
 
 	nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1"
@@ -40,9 +43,12 @@ const NvFeature = "nv"
 // NumaFeature is the name of the feature set that holds all NUMA related features.
 const NumaFeature = "numa"
 
-// SwapFeature is the name of the feature set that holds all Swap related features
+// SwapFeature is the name of the feature set that holds all Swap related features.
 const SwapFeature = "swap"
 
+// HugePages is the name of the feature set that holds information about huge pages.
+const HugePages = "hugepages"
+
 // memorySource implements the FeatureSource and LabelSource interfaces.
 type memorySource struct {
 	features *nfdv1alpha1.Features
@@ -115,6 +121,13 @@ func (s *memorySource) Discover() error {
 		s.features.Instances[NvFeature] = nfdv1alpha1.InstanceFeatureSet{Elements: nv}
 	}
 
+	// Detect Huge Pages
+	if hp, err := detectHugePages(); err != nil {
+		klog.ErrorS(err, "failed to detect huge pages")
+	} else {
+		s.features.Attributes[HugePages] = nfdv1alpha1.AttributeFeatureSet{Elements: hp}
+	}
+
 	klog.V(3).InfoS("discovered features", "featureSource", s.Name(), "features", utils.DelayedDumper(s.features))
 
 	return nil
@@ -179,6 +192,57 @@ func detectNv() ([]nfdv1alpha1.InstanceFeature, error) {
 	return info, nil
 }
 
+// detectHugePages checks whether huge pages are enabled on the node
+// and retrieves the configured huge page sizes.
+func detectHugePages() (map[string]string, error) {
+	hugePages := map[string]string{
+		"enabled": "false",
+	}
+
+	basePath := hostpath.SysfsDir.Path("kernel/mm/hugepages")
+	subdirs, err := os.ReadDir(basePath)
+	if err != nil {
+		if errors.Is(err, os.ErrNotExist) {
+			return hugePages, nil
+		}
+		return nil, fmt.Errorf("unable to read huge pages size: %w", err)
+	}
+
+	for _, entry := range subdirs {
+		if !entry.IsDir() {
+			continue
+		}
+
+		totalPages, err := getHugePagesTotalCount(basePath, entry.Name())
+		if err != nil {
+			klog.ErrorS(err, "unable to read hugepages total count", "hugepages", entry.Name())
+		}
+		pageSize := strings.TrimRight(strings.TrimPrefix(entry.Name(), "hugepages-"), "kB")
+		quantity, err := resource.ParseQuantity(pageSize + "Ki")
+		if err != nil {
+			klog.ErrorS(err, "unable to parse quantity", "hugepages", entry.Name(), "pageSize", pageSize)
+			continue
+		}
+
+		hugePages[corev1.ResourceHugePagesPrefix+quantity.String()] = totalPages
+		if v, err := strconv.Atoi(totalPages); err == nil && v > 0 {
+			hugePages["enabled"] = "true"
+		}
+	}
+
+	return hugePages, nil
+}
+
+func getHugePagesTotalCount(basePath, dirname string) (string, error) {
+	totalPagesFile := filepath.Join(basePath, dirname, "nr_hugepages")
+	totalPages, err := os.ReadFile(totalPagesFile)
+	if err != nil {
+		return "", fmt.Errorf("unable to read total number of huge pages from the file: %s", totalPagesFile)
+	}
+
+	return strings.TrimSpace(string(totalPages)), nil
+}
+
 // ndDevAttrs is the list of sysfs files (under each nd device) that we're trying to read
 var ndDevAttrs = []string{"devtype", "mode"}
 
diff --git a/source/mock_LabelSource.go b/source/mock_LabelSource.go
index b9bfdb6f4..07ae9b429 100644
--- a/source/mock_LabelSource.go
+++ b/source/mock_LabelSource.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.52.2. DO NOT EDIT.
+// Code generated by mockery v2.42.0. DO NOT EDIT.
 
 package source
 
@@ -9,7 +9,7 @@ type MockLabelSource struct {
 	mock.Mock
 }
 
-// GetLabels provides a mock function with no fields
+// GetLabels provides a mock function with given fields:
 func (_m *MockLabelSource) GetLabels() (FeatureLabels, error) {
 	ret := _m.Called()
 
@@ -39,7 +39,7 @@ func (_m *MockLabelSource) GetLabels() (FeatureLabels, error) {
 	return r0, r1
 }
 
-// Name provides a mock function with no fields
+// Name provides a mock function with given fields:
 func (_m *MockLabelSource) Name() string {
 	ret := _m.Called()
 
@@ -57,7 +57,7 @@ func (_m *MockLabelSource) Name() string {
 	return r0
 }
 
-// Priority provides a mock function with no fields
+// Priority provides a mock function with given fields:
 func (_m *MockLabelSource) Priority() int {
 	ret := _m.Called()
 


Test patch:
diff --git a/scripts/test-infra/verify.sh b/scripts/test-infra/verify.sh
index c6b957c28..bd041d0f4 100755
--- a/scripts/test-infra/verify.sh
+++ b/scripts/test-infra/verify.sh
@@ -4,7 +4,7 @@ this_dir=`dirname $0`
 
 # Install deps
 gobinpath="$(go env GOPATH)/bin"
-curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s -- -b "$gobinpath" v1.64.5
+curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s -- -b "$gobinpath" v1.60.3
 export PATH=$PATH:$(go env GOPATH)/bin
 
 curl -sfL https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash -s -- --version v3.15.3
diff --git a/source/memory/memory_test.go b/source/memory/memory_test.go
index 535decb03..85aea9e96 100644
--- a/source/memory/memory_test.go
+++ b/source/memory/memory_test.go
@@ -19,7 +19,10 @@ package memory
 import (
 	"testing"
 
+	. "github.com/smartystreets/goconvey/convey"
 	"github.com/stretchr/testify/assert"
+
+	"sigs.k8s.io/node-feature-discovery/pkg/utils/hostpath"
 )
 
 func TestMemorySource(t *testing.T) {
@@ -61,3 +64,53 @@ func TestGetNumberofLinesFromFile(t *testing.T) {
 		assert.Equal(t, tc.expectedLines, actual, "lines should match")
 	}
 }
+
+func TestDetectHugePages(t *testing.T) {
+
+	Convey("With configured 1Gi huge pages size", t, func() {
+		hostpath.SysfsDir = "testdata/hugepages"
+
+		expectedHugePages := map[string]string{
+			"enabled":       "true",
+			"hugepages-1Gi": "2",
+			"hugepages-2Mi": "0",
+		}
+		hugePages, err := detectHugePages()
+		assert.Nil(t, err)
+		assert.Equal(t, hugePages, expectedHugePages)
+	})
+
+	Convey("With invalid directory structure", t, func() {
+		hostpath.SysfsDir = "invalid-dir"
+
+		expectedHugePages := map[string]string{
+			"enabled": "false",
+		}
+		hugePages, err := detectHugePages()
+		assert.Nil(t, err)
+		assert.Equal(t, hugePages, expectedHugePages)
+	})
+
+}
+
+func TestGetHugePagesTotalCount(t *testing.T) {
+
+	Convey("With configured total huge pages", t, func() {
+		totalPages, err := getHugePagesTotalCount("testdata/hugepages/kernel/mm/hugepages", "hugepages-1048576kB")
+		assert.Equal(t, "2", totalPages)
+		assert.Nil(t, err)
+	})
+
+	Convey("With not configured total huge pages", t, func() {
+		totalPages, err := getHugePagesTotalCount("testdata/hugepages/kernel/mm/hugepages", "hugepages-2048kB")
+		assert.Equal(t, "0", totalPages)
+		assert.Nil(t, err)
+	})
+
+	Convey("With invalid huge page directory", t, func() {
+		totalPages, err := getHugePagesTotalCount("testdata/hugepages/kernel/mm/hugepages", "hugepages-invalid")
+		assert.Equal(t, "", totalPages)
+		assert.NotNil(t, err)
+	})
+
+}
diff --git a/source/memory/testdata/hugepages/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages b/source/memory/testdata/hugepages/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages
new file mode 100644
index 000000000..0cfbf0888
--- /dev/null
+++ b/source/memory/testdata/hugepages/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages
@@ -0,0 +1,1 @@
+2
diff --git a/source/memory/testdata/hugepages/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages b/source/memory/testdata/hugepages/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
new file mode 100644
index 000000000..573541ac9
--- /dev/null
+++ b/source/memory/testdata/hugepages/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
@@ -0,0 +1,1 @@
+0
diff --git a/test/e2e/node_feature_discovery_test.go b/test/e2e/node_feature_discovery_test.go
index 78cb96eee..54c3b1458 100644
--- a/test/e2e/node_feature_discovery_test.go
+++ b/test/e2e/node_feature_discovery_test.go
@@ -47,7 +47,6 @@ import (
 	"sigs.k8s.io/node-feature-discovery/source/custom"
 	testutils "sigs.k8s.io/node-feature-discovery/test/e2e/utils"
 	testds "sigs.k8s.io/node-feature-discovery/test/e2e/utils/daemonset"
-	"sigs.k8s.io/node-feature-discovery/test/e2e/utils/namespace"
 	testpod "sigs.k8s.io/node-feature-discovery/test/e2e/utils/pod"
 )
 
@@ -1012,7 +1011,20 @@ resyncPeriod: "1s"
 				Expect(targetNodeName).ToNot(BeEmpty(), "No suitable worker node found")
 
 				// label the namespace in which node feature object is created
-				err = namespace.PatchLabels(f.Namespace.Name, "e2etest", "fake", utils.JSONAddOperation, ctx, f)
+				// TODO(TessaIO): add a utility for this.
+				patches, err := json.Marshal(
+					[]utils.JsonPatch{
+						utils.NewJsonPatch(
+							"add",
+							"/metadata/labels",
+							"e2etest",
+							"fake",
+						),
+					},
+				)
+				Expect(err).NotTo(HaveOccurred())
+
+				_, err = f.ClientSet.CoreV1().Namespaces().Patch(ctx, f.Namespace.Name, types.JSONPatchType, patches, metav1.PatchOptions{})
 				Expect(err).NotTo(HaveOccurred())
 
 				// Apply Node Feature object
@@ -1032,9 +1044,20 @@ resyncPeriod: "1s"
 				eventuallyNonControlPlaneNodes(ctx, f.ClientSet).Should(MatchLabels(expectedLabels, nodes))
 
 				// remove label the namespace in which node feature object is created
-				err = namespace.PatchLabels(f.Namespace.Name, "e2etest", "fake", utils.JSONRemoveOperation, ctx, f)
+				patches, err = json.Marshal(
+					[]utils.JsonPatch{
+						utils.NewJsonPatch(
+							"remove",
+							"/metadata/labels",
+							"e2etest",
+							"fake",
+						),
+					},
+				)
 				Expect(err).NotTo(HaveOccurred())
 
+				_, err = f.ClientSet.CoreV1().Namespaces().Patch(ctx, f.Namespace.Name, types.JSONPatchType, patches, metav1.PatchOptions{})
+				Expect(err).NotTo(HaveOccurred())
 				By("Verifying node labels from NodeFeature object #1 are not created")
 				// No labels should be created since the f.Namespace is not in the selected Namespaces
 				expectedLabels = map[string]k8sLabels{
@@ -1184,19 +1207,6 @@ restrictions:
 				Expect(err).NotTo(HaveOccurred())
 			})
 			It("No feature labels should be created", func(ctx context.Context) {
-				// deploy worker to make sure that labels created by worker are not ignored by denyNodeFeatureLabels restriction
-				By("Creating nfd-worker daemonset")
-				podSpecOpts := []testpod.SpecOption{
-					testpod.SpecWithContainerImage(dockerImage()),
-					testpod.SpecWithContainerExtraArgs("-label-sources=fake"),
-				}
-				workerDS := testds.NFDWorker(podSpecOpts...)
-				workerDS, err := f.ClientSet.AppsV1().DaemonSets(f.Namespace.Name).Create(ctx, workerDS, metav1.CreateOptions{})
-				Expect(err).NotTo(HaveOccurred())
-
-				By("Waiting for worker daemonset pods to be ready")
-				Expect(testpod.WaitForReady(ctx, f.ClientSet, f.Namespace.Name, workerDS.Spec.Template.Labels["name"], 2)).NotTo(HaveOccurred())
-
 				// deploy node feature object
 				nodes, err := getNonControlPlaneNodes(ctx, f.ClientSet)
 				Expect(err).NotTo(HaveOccurred())
@@ -1224,7 +1234,7 @@ restrictions:
 						"e2e.feature.node.kubernetes.io/restricted-annoation-1": "yes",
 						"nfd.node.kubernetes.io/feature-annotations":            "e2e.feature.node.kubernetes.io/restricted-annoation-1",
 						"nfd.node.kubernetes.io/extended-resources":             "e2e.feature.node.kubernetes.io/restricted-er-1",
-						"nfd.node.kubernetes.io/feature-labels":                 "e2e.feature.node.kubernetes.io/restricted-label-1,fake-fakefeature1,fake-fakefeature2,fake-fakefeature3",
+						"nfd.node.kubernetes.io/feature-labels":                 "e2e.feature.node.kubernetes.io/restricted-label-1",
 					},
 				}
 				eventuallyNonControlPlaneNodes(ctx, f.ClientSet).Should(MatchAnnotations(expectedAnnotations, nodes))
@@ -1236,12 +1246,11 @@ restrictions:
 				}
 				eventuallyNonControlPlaneNodes(ctx, f.ClientSet).WithTimeout(1 * time.Minute).Should(MatchCapacity(expectedCapacity, nodes))
 
+				// TODO(TessaIO): we need one more test where we deploy nfd-worker that would create
+				// a non 3rd-party NF that shouldn't be ignored by this restriction
 				By("Verifying node labels from NodeFeature object #6 are not created")
 				expectedLabels := map[string]k8sLabels{
 					"*": {
-						nfdv1alpha1.FeatureLabelNs + "/fake-fakefeature1":   "true",
-						nfdv1alpha1.FeatureLabelNs + "/fake-fakefeature2":   "true",
-						nfdv1alpha1.FeatureLabelNs + "/fake-fakefeature3":   "true",
 						"e2e.feature.node.kubernetes.io/restricted-label-1": "true",
 					},
 				}
diff --git a/test/e2e/utils/namespace/namespace.go b/test/e2e/utils/namespace/namespace.go
deleted file mode 100644
index bd30bbab4..000000000
--- a/test/e2e/utils/namespace/namespace.go
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-Copyright 2024 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package namespace
-
-import (
-	"context"
-	"encoding/json"
-	"fmt"
-
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/types"
-	"k8s.io/kubernetes/test/e2e/framework"
-
-	"sigs.k8s.io/node-feature-discovery/pkg/utils"
-)
-
-// PatchLabels updates the given label for a specific namespace with a given value
-func PatchLabels(name, key, value, operation string, ctx context.Context, f *framework.Framework) error {
-	if operation != utils.JSONAddOperation && operation != utils.JSONRemoveOperation {
-		return fmt.Errorf("unknown operation type, known values are %s, %s", utils.JSONAddOperation, utils.JSONRemoveOperation)
-	}
-
-	patches, err := json.Marshal(
-		[]utils.JsonPatch{
-			utils.NewJsonPatch(
-				operation,
-				"/metadata/labels",
-				key,
-				value,
-			),
-		},
-	)
-	if err != nil {
-		return err
-	}
-
-	_, err = f.ClientSet.CoreV1().Namespaces().Patch(ctx, name, types.JSONPatchType, patches, metav1.PatchOptions{})
-	return err
-}