Repository: gardener/machine-controller-manager

Issue:
prefer-no-schedule taint sticks forever if oldMS --> newMS --> oldMS
**How to categorize this issue?**
/area robustness
/kind bug
/priority 3

**What happened**:
a `machineSet` keeps the taint `prefer-no-schedule` forever

**What you expected to happen**:
the taint is removed

**How to reproduce it (as minimally and precisely as possible)**:
have a machienset with rolling update strategy. have a worker definition like so

```
      - cri:
          name: containerd
        name: standard-16
        machine:
          type: n2-standard-16
          image:
            name: ubuntu
            version: 22.0.4
          architecture: amd64
        maximum: 10
        minimum: 1
        maxSurge: 1
        maxUnavailable: 0
        volume:
          type: pd-standard
          size: 800Gi
        zones:
          - europe-west1-b
        systemComponents:
          allow: true
```

change the worker image

```
      - cri:
          name: containerd
        name: standard-16
        machine:
          type: n2-standard-16
          image:
            name: flatcar
            version: 9999.9.9
          architecture: amd64
        maximum: 10
        minimum: 1
        maxSurge: 1
        maxUnavailable: 0
        volume:
          type: pd-standard
          size: 800Gi
        zones:
          - europe-west1-b
        systemComponents:
          allow: true
```

Wait for the new machineset to be created. 
Change the worker definition back to what it was before:

```
      - cri:
          name: containerd
        name: standard-16
        machine:
          type: n2-standard-16
          image:
            name: ubuntu
            version: 22.0.4
          architecture: amd64
        maximum: 10
        minimum: 1
        maxSurge: 1
        maxUnavailable: 0
        volume:
          type: pd-standard
          size: 800Gi
        zones:
          - europe-west1-b
        systemComponents:
          allow: true
```
The "new" machineset will be deleted, the old one will be kept, but tainted, resulting in the machines to be tainted.

**Environment**:

:
- Others:
machine-controller-manager:v0.53.0


Discussion:
@gardener-robot: @RiRa12621 Label area/todo does not exist.@RiRa12621: /area robustness@RiRa12621: /cc @schrodit @gnarlex

Solution patch:
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index c0e54cba1..4918f9b41 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -5,6 +5,8 @@ labels: kind/bug
 
 ---
 
+<!-- Please ensure that you do not include company internal information. -->
+
 **How to categorize this issue?**
 <!--
 Please select area, kind, and priority for this issue. This helps the community categorizing it.
diff --git a/.github/ISSUE_TEMPLATE/enhancement_request.md b/.github/ISSUE_TEMPLATE/enhancement_request.md
index 4b5776400..ba12b32b6 100644
--- a/.github/ISSUE_TEMPLATE/enhancement_request.md
+++ b/.github/ISSUE_TEMPLATE/enhancement_request.md
@@ -5,6 +5,8 @@ labels: kind/enhancement
 
 ---
 
+<!-- Please ensure that you do not include company internal information. -->
+
 **How to categorize this issue?**
 <!--
 Please select area, kind, and priority for this issue. This helps the community categorizing it.
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index b98e19a70..fada1a137 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -1,3 +1,5 @@
+<!-- Please ensure that you do not include company internal information. -->
+
 **What this PR does / why we need it**:
 
 **Which issue(s) this PR fixes**:
diff --git a/.github/workflows/pr-release-notes-validation.yaml b/.github/workflows/pr-release-notes-validation.yaml
new file mode 100644
index 000000000..9bebced53
--- /dev/null
+++ b/.github/workflows/pr-release-notes-validation.yaml
@@ -0,0 +1,18 @@
+name: Validate release-notes from PRs
+on:
+  pull_request:
+    types:
+      - opened
+      - edited
+      - reopened
+
+permissions:
+  pull-requests: read
+
+jobs:
+  validate-release-notes:
+    uses: gardener/cc-utils/.github/workflows/validate-release-notes.yaml@master
+    permissions:
+      pull-requests: read
+    with:
+      pull-request-body: ${{ github.event.pull_request.body }}
diff --git a/.ocm/branch-info.yaml b/.ocm/branch-info.yaml
new file mode 100644
index 000000000..104090d5b
--- /dev/null
+++ b/.ocm/branch-info.yaml
@@ -0,0 +1,5 @@
+release-branch-template: rel-v$major.$minor # e.g. rel-v1.0
+branch-policy:
+  significant-part: minor # major, minor, patch
+  supported-versions-count: 2
+  release-cadence: null # d (days), w (weeks), y | yr (years)
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 000000000..bfa50f938
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,6 @@
+# See the OWNERS docs at https://go.k8s.io/owners
+
+reviewers:
+- machine-controller-manager-reviewers
+approvers:
+- machine-controller-manager-approvers
diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES
new file mode 100644
index 000000000..28282fb46
--- /dev/null
+++ b/OWNERS_ALIASES
@@ -0,0 +1,21 @@
+# See the OWNERS docs at https://go.k8s.io/owners
+
+aliases:
+  machine-controller-manager-reviewers:
+  - aaronfern
+  - ashwani2k
+  - elankath
+  - gagan16k
+  - kon-angelo
+  - takoverflow
+  - thiyyakat
+  - unmarshall
+  machine-controller-manager-approvers:
+  - aaronfern
+  - ashwani2k
+  - elankath
+  - gagan16k
+  - kon-angelo
+  - takoverflow
+  - thiyyakat
+  - unmarshall
diff --git a/README.md b/README.md
index fe5a20bd6..6322596ab 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ Machine Controller Manager aka MCM is a group of cooperative controllers that ma
 - transport the immutability design principle to machine/nodes
 - implement e.g. rolling upgrades of machines/nodes
 
-MCM supports following providers. These provider code is maintained externally (out-of-tree), and the links for the same are linked below: 
+MCM supports the following providers. This provider code is maintained externally (out-of-tree), and the links for the same are linked below: 
 * [Alicloud](https://github.com/gardener/machine-controller-manager-provider-alicloud)
 * [AWS](https://github.com/gardener/machine-controller-manager-provider-aws)
 * [Azure](https://github.com/gardener/machine-controller-manager-provider-azure)
@@ -31,7 +31,7 @@ MCM supports following providers. These provider code is maintained externally (
 
 It can easily be extended to support other cloud providers as well.
 
-Example of managing machine:
+Example of managing a machine:
 ```
 kubectl create/get/delete machine vm1
 ```
@@ -46,7 +46,7 @@ Nodes/Machines/VMs are different terminologies used to represent similar things.
 
 # Design of Machine Controller Manager
 
-The design of the Machine Controller Manager is influenced by the Kube Controller Manager, where-in multiple sub-controllers are used to manage the Kubernetes clients.
+The design of the Machine Controller Manager is influenced by the Kube Controller Manager, wherein multiple sub-controllers are used to manage the Kubernetes clients.
 
 ## Design Principles
 
@@ -66,7 +66,7 @@ Machine Controller Manager reconciles a set of Custom Resources namely `MachineD
 
 Machine Controller Manager makes use of 4 CRD objects and 1 Kubernetes secret object to manage machines. They are as follows:
 
-| Custom ResourceObject | Description |
+| Custom Resource Object | Description |
 | --- | --- |
 | `MachineClass`| A `MachineClass` represents a template that contains cloud provider specific details used to create machines.|
 | `Machine`| A `Machine` represents a VM which is backed by the cloud provider.|
@@ -114,7 +114,7 @@ See [here](docs/documents/apis.md) for CRD API Documentation
     </tbody>
 </table>
 
-Along with the above Custom Controllers and Resources, MCM requires the `MachineClass` to use K8s `Secret` that stores cloudconfig (initialization scripts used to create VMs) and cloud specific credentials. All these controllers work in an co-operative manner. They form a parent-child relationship with `MachineDeployment` Controller being the grandparent, `MachineSet` Controller being the parent, and `Machine` Controller being the child.
+Along with the above Custom Controllers and Resources, MCM requires the `MachineClass` to use K8s `Secret` that stores cloudconfig (initialization scripts used to create VMs) and cloud specific credentials. All these controllers work in a co-operative manner. They form a parent-child relationship with `MachineDeployment` Controller being the grandparent, `MachineSet` Controller being the parent, and `Machine` Controller being the child.
 
 
 ## Development
@@ -122,9 +122,9 @@ Along with the above Custom Controllers and Resources, MCM requires the `Machine
 To start using or developing the Machine Controller Manager, see the documentation in the `/docs` repository.
 
 ## FAQ
-An FAQ is available [here](docs/FAQ.md).
+An FAQ is available [here](docs/faq.md).
 
 ## cluster-api Implementation
 - `cluster-api` branch of machine-controller-manager implements the machine-api aspect of the [cluster-api project](https://github.com/kubernetes-sigs/cluster-api).
 - Link: https://github.com/gardener/machine-controller-manager/tree/cluster-api
-- Once cluster-api project gets stable, we may make `master` branch of MCM as well cluster-api compliant, with well-defined migration notes.
+- Once the cluster-api project becomes stable, we may make `master` branch of MCM as well cluster-api compliant, with well-defined migration notes.
diff --git a/cmd/machine-controller-manager/app/controllermanager.go b/cmd/machine-controller-manager/app/controllermanager.go
index a0c7aeaf2..ba8adf232 100644
--- a/cmd/machine-controller-manager/app/controllermanager.go
+++ b/cmd/machine-controller-manager/app/controllermanager.go
@@ -313,7 +313,7 @@ func getAvailableResources(clientBuilder corecontroller.ClientBuilder) (map[sche
 	var healthzContent string
 	// If apiserver is not running we should wait for some time and fail only then. This is particularly
 	// important when we start apiserver and controller manager at the same time.
-	err := wait.PollImmediate(time.Second, 10*time.Second, func() (bool, error) {
+	err := wait.PollUntilContextTimeout(context.Background(), 1*time.Second, 10*time.Second, true, func(_ context.Context) (bool, error) {
 		client, err := clientBuilder.Client("controller-discovery")
 		if err != nil {
 			klog.Errorf("Failed to get api versions from server: %v", err)
diff --git a/docs/development/machine_error_codes.md b/docs/development/machine_error_codes.md
index 13f148065..62cbc0ae5 100644
--- a/docs/development/machine_error_codes.md
+++ b/docs/development/machine_error_codes.md
@@ -451,7 +451,7 @@ to be supplied as the `ProviderSpecificMachineClass`. The provider is responsibl
 type GenerateMachineClassForMigrationRequest struct {
 	// ProviderSpecificMachineClass is provider specfic machine class object.
 	// E.g. AWSMachineClass
-	ProviderSpecificMachineClass interface{}
+	ProviderSpecificMachineClass any
 	// MachineClass is the machine class object generated that is to be filled up
 	MachineClass *v1alpha1.MachineClass
 	// ClassSpec contains the class spec object to determine the machineClass kind
diff --git a/docs/FAQ.md b/docs/faq.md
similarity index 100%
rename from docs/FAQ.md
rename to docs/faq.md
diff --git a/docs/proposals/machine-preservation.md b/docs/proposals/machine-preservation.md
new file mode 100644
index 000000000..bf92d3c0b
--- /dev/null
+++ b/docs/proposals/machine-preservation.md
@@ -0,0 +1,163 @@
+# Preservation of Machines
+
+<!-- TOC -->
+
+- [Preservation of Machines](#preservation-of-machines)
+    - [Objective](#objective)
+    - [Proposal](#proposal)
+    - [State Diagrams](#state-diagrams)
+    - [Use Cases](#use-cases)
+
+<!-- /TOC -->
+
+## Objective
+
+Currently, the Machine Controller Manager(MCM) moves Machines with errors to the `Unknown` phase, and after the configured `machineHealthTimeout`, to the `Failed` phase.
+`Failed` machines are swiftly moved to the `Terminating` phase during which the node is drained and the `Machine` object is deleted. This rapid cleanup prevents SRE/operators/support from conducting an analysis on the VM and makes finding root cause of failure more difficult.
+
+Moreover, in cases where a node seems healthy but all the workload on it are facing issues, there is a need for operators to be able to cordon/drain the node and conduct their analysis without the cluster-autoscaler (CA) scaling down the node.
+
+This document proposes enhancing MCM, such that:
+* VMs of machines are retained temporarily for analysis.
+* There is a configurable limit to the number of machines that can be preserved automatically on failure (auto-preservation).
+* There is a configurable limit to the duration for which machines are preserved.
+* Users can specify which healthy machines they would like to preserve in case of failure, or for diagnoses in current state (prevent scale down by CA).
+* Users can request MCM to release a preserved machine, even before the timeout expires, so that MCM can transition the machine to either `Running` or `Terminating` phase, as the case may be.
+
+Related Issue: https://github.com/gardener/machine-controller-manager/issues/1008
+
+## Proposal
+
+In order to achieve the objectives mentioned, the following are proposed:
+1. Enhance `machineControllerManager` configuration in the `ShootSpec`, to specify the max number of machines to be auto-preserved,
+and the time duration for which these machines will be preserved.
+    ```
+    machineControllerManager:
+       autoPreserveFailedMax: 0
+       machinePreserveTimeout: 72h
+    ```
+    * This configuration will be set per worker pool.
+    * Since gardener worker pool can correspond to `1..N` MachineDeployments depending on number of zones, `autoPreserveFailedMax` will be distributed across N machine deployments.
+    * `autoPreserveFailedMax` must be chosen such that it can be appropriately distributed across the MachineDeployments.
+    * Example: if `autoPreserveFailedMax` is set to 2, and the worker pool has 2 zones, then the maximum number of machines that will be preserved per zone is 1.
+2. MCM will be modified to include a new sub-phase `Preserved` to indicate that the machine has been preserved by MCM.
+3. Allow user/operator to request for preservation of a specific machine/node with the use of annotations : `node.machine.sapcloud.io/preserve=now` and `node.machine.sapcloud.io/preserve=when-failed`.
+4. When annotation `node.machine.sapcloud.io/preserve=now` is added to a `Running` machine, the following will take place:
+   - `cluster-autoscaler.kubernetes.io/scale-down-disabled: "true"` is added to the node to prevent CA from scaling it down.
+   - `machine.CurrentStatus.PreserveExpiryTime` is updated by MCM as $machine.CurrentStatus.PreserveExpiryTime = currentTime+machinePreserveTimeout$.
+   - The machine's phase is changed to `Running:Preserved`.
+   - After timeout, the `node.machine.sapcloud.io/preserve=now` and `cluster-autoscaler.kubernetes.io/scale-down-disabled: "true"` are deleted. The `machine.CurrentStatus.PreserveExpiryTime` is set to `nil`. The machine phase is changed to `Running` and the CA may delete the node.
+     - If a machine in `Running:Preserved` fails, it is moved to `Failed:Preserved`.
+5. When annotation `node.machine.sapcloud.io/preserve=when-failed` is added to a `Running` machine and the machine goes to `Failed`, the following will take place:
+    - The machine is drained of pods except for Daemonset pods.
+    - The machine phase is changed to `Failed:Preserved`.
+    - `cluster-autoscaler.kubernetes.io/scale-down-disabled: "true"` is added to the node to prevent CA from scaling it down.
+    - `machine.CurrentStatus.PreserveExpiryTime` is updated by MCM as $machine.CurrentStatus.PreserveExpiryTime = currentTime+machinePreserveTimeout$.
+    - After timeout, the annotations `node.machine.sapcloud.io/preserve=when-failed` and `cluster-autoscaler.kubernetes.io/scale-down-disabled: "true"` are deleted. `machine.CurrentStatus.PreserveExpiryTime` is set to `nil`. The phase is changed to `Terminating`.
+6. When an un-annotated machine goes to `Failed` phase and `autoPreserveFailedMax` is not breached:
+   - Pods (other than DaemonSet pods) are drained.
+   - The machine's phase is changed to `Failed:Preserved`.
+   - `cluster-autoscaler.kubernetes.io/scale-down-disabled: "true"` is added to the node to prevent CA from scaling it down.
+   - `machine.CurrentStatus.PreserveExpiryTime` is updated by MCM as $machine.CurrentStatus.PreserveExpiryTime = currentTime+machinePreserveTimeout$.
+   - After timeout, the annotation `cluster-autoscaler.kubernetes.io/scale-down-disabled: "true"` is deleted. `machine.CurrentStatus.PreserveExpiryTime` is set to `nil`. The phase is changed to `Terminating`.
+   - Number of machines in `Failed:Preserved` phase count towards enforcing `autoPreserveFailedMax`.
+7. If a failed machine is currently in `Failed:Preserved` and before timeout its VM/node is found to be Healthy, the machine will be moved to `Running:Preserved`. After the timeout, it will be moved to `Running`. 
+The rationale behind moving the machine to `Running:Preserved` rather than `Running`, is to allow pods to get scheduled on to the healthy node again without the autoscaler scaling it down due to under-utilization. 
+8. A user/operator can request MCM to stop preserving a machine/node in `Running:Preserved` or `Failed:Preserved` phase using the annotation: `node.machine.sapcloud.io/preserve=false`. 
+   * MCM will move a machine thus annotated either to `Running` phase or `Terminating` depending on the phase of the machine before it was preserved.
+9. Machines of a MachineDeployment in `Preserved` sub-phase will also be counted towards the replica count and in the enforcement of maximum machines allowed for the MachineDeployment.
+10. MCM will be modified to perform drain in `Failed` phase rather than `Terminating`.
+
+## State Diagrams:
+
+1. State Diagram for when a machine or its node is explicitly annotated for preservation:
+    ```mermaid
+    stateDiagram-v2
+        state "Running" as R
+        state "Running + Requested" as RR
+        state "Running:Preserved" as RP
+        state "Failed
+        (node drained)" as F
+        state "Failed:Preserved" as FP
+        state "Terminating" as T
+        [*]-->R
+        R --> RR: annotated with preserve=when-failed
+        RP-->R: on timeout or preserve=false
+        RR --> F: on failure
+        F --> FP
+        FP --> T: on timeout or preserve=false
+        FP --> RP: if node Healthy before timeout
+        T --> [*]
+        R-->RP: annotated with preserve=now
+        RP-->F: if node/VM not healthy
+    ```
+2. State Diagram for when an un-annotated `Running` machine fails (Auto-preservation):
+    ```mermaid
+    stateDiagram-v2
+        state "Running" as R
+        state "Running:Preserved" as RP
+        state "Failed
+        (node drained)" as F
+        state "Failed:Preserved" as FP
+        state "Terminating" as T
+        [*] --> R
+        R-->F: on failure
+        F --> FP: if autoPreserveFailedMax not breached
+        F --> T: if autoPreserveFailedMax breached
+        FP --> T: on timeout or value=false
+        FP --> RP : if node Healthy before timeout
+        RP --> R: on timeout or preserve=false
+        T --> [*]
+    ```
+
+## Use Cases:
+
+### Use Case 1: Preservation Request for Analysing Running Machine
+**Scenario:** Workload on machine failing. Operator wishes to diagnose.
+#### Steps:
+1. Operator annotates node with `node.machine.sapcloud.io/preserve=now`.
+2. MCM preserves the machine, and prevents CA from scaling it down.
+3. Operator analyzes the VM.
+
+### Use Case 2: Proactive Preservation Request
+**Scenario:** Operator suspects a machine might fail and wants to ensure preservation for analysis.
+#### Steps:
+1. Operator annotates node with `node.machine.sapcloud.io/preserve=when-failed`.
+2. Machine fails later.
+3. MCM preserves the machine. 
+4. Operator analyzes the VM.
+
+
+### Use Case 3: Auto-Preservation
+**Scenario:** Machine fails unexpectedly, no prior annotation.
+#### Steps:
+1. Machine transitions to `Failed` phase.
+2. Machine is drained.
+3. If `autoPreserveFailedMax` is not breached, machine moved to `Failed:Preserved` phase by MCM.
+4. After `machinePreserveTimeout`, machine is terminated by MCM.
+
+### Use Case 4: Early Release
+**Scenario:** Operator has performed his analysis and no longer requires machine to be preserved.
+#### Steps:
+1. Machine is in `Running:Preserved` or `Failed:Preserved` phase.
+2. Operator adds: `node.machine.sapcloud.io/preserve=false` to node.
+3. MCM transitions machine to `Running` or `Terminating` for `Running:Preserved` or `Failed:Preserved` respectively, even though `machinePreserveTimeout` has not expired.
+4. If machine was in `Failed:Preserved`, capacity becomes available for auto-preservation.
+
+## Points to Note
+
+1. During rolling updates MCM will NOT honor preserving Machines. The Machine will be replaced with a healthy one if it moves to Failed phase.
+2. Hibernation policy will override machine preservation. 
+3. Consumers (with access to shoot cluster) can annotate Nodes they would like to preserve.
+4. Operators (with access to control plane) can additionally annotate Machines that they would like to preserve. This feature can be used when a Machine does not have a backing Node and the operator wishes to preserve the backing VM.
+5. If the backing Node object exists but does not have the preservation annotation, preservation annotations added on the Machine will be honoured.
+6. However, if a backing Node exists for a Machine and has the preservation annotation, the Node's annotation value will override the Machine annotation value, and be synced to the Machine object.
+7. If `autoPreserveFailedMax` is reduced in the Shoot Spec, older machines are moved to `Terminating` phase before newer ones.
+8. In case of a scale down of an MCD's replica count, `Preserved` machines will be the last to be scaled down. Replica count will always be honoured.
+9. If the value for annotation key `cluster-autoscaler.kubernetes.io/scale-down-disabled` for a machine in `Running:Preserved` is changed to `false` by a user, the value will be overwritten to `true` by MCM.
+10. On increase/decrease of timeout, the new value will only apply to machines that go into `Preserved` phase after the change. Operators can always edit `machine.CurrentStatus.PreserveExpiryTime` to prolong the expiry time of existing `Preserved` machines.
+11. [Modify CA FAQ](https://github.com/gardener/autoscaler/blob/master/cluster-autoscaler/FAQ.md#how-can-i-prevent-cluster-autoscaler-from-scaling-down-a-particular-node) once feature is developed to use `node.machine.sapcloud.io/preserve=now` instead of the `cluster-autoscaler.kubernetes.io/scale-down-disabled=true` currently suggested. This would:
+   - harmonise machine flow
+   - shield from CA's internals
+   - make it generic and no longer CA specific
+   - allow a timeout to be specified
\ No newline at end of file
diff --git a/kubernetes/deployment/out-of-tree/target-cluster-role.yaml b/kubernetes/deployment/out-of-tree/target-cluster-role.yaml
index 20f774edf..1edf3ce26 100644
--- a/kubernetes/deployment/out-of-tree/target-cluster-role.yaml
+++ b/kubernetes/deployment/out-of-tree/target-cluster-role.yaml
@@ -64,3 +64,4 @@ rules:
   - get
   - list
   - watch
+  - delete
diff --git a/pkg/apis/machine/validation/machinedeployment.go b/pkg/apis/machine/validation/machinedeployment.go
index a63b023cd..7374629c8 100644
--- a/pkg/apis/machine/validation/machinedeployment.go
+++ b/pkg/apis/machine/validation/machinedeployment.go
@@ -8,7 +8,7 @@ package validation
 import (
 	"fmt"
 	"math"
-	"sort"
+	"slices"
 
 	"github.com/gardener/machine-controller-manager/pkg/apis/machine"
 	"k8s.io/apimachinery/pkg/util/intstr"
@@ -44,7 +44,7 @@ func validateUpdateStrategy(spec *machine.MachineDeploymentSpec, fldPath *field.
 	supportedStrategies := sets.New(machine.RecreateMachineDeploymentStrategyType, machine.RollingUpdateMachineDeploymentStrategyType, machine.InPlaceUpdateMachineDeploymentStrategyType)
 	if !supportedStrategies.Has(spec.Strategy.Type) {
 		strategies := supportedStrategies.UnsortedList()
-		sort.Slice(strategies, func(i, j int) bool { return strategies[i] < strategies[j] })
+		slices.Sort(strategies)
 		allErrs = append(allErrs, field.Invalid(fldPath.Child("strategy.type"), spec.Strategy.Type, fmt.Sprintf("strategy type must be one of %v", strategies)))
 	}
 
diff --git a/pkg/client/listers/machine/v1alpha1/machine.go b/pkg/client/listers/machine/v1alpha1/machine.go
index 8ab17f6f4..68c6b4c10 100644
--- a/pkg/client/listers/machine/v1alpha1/machine.go
+++ b/pkg/client/listers/machine/v1alpha1/machine.go
@@ -36,7 +36,7 @@ func NewMachineLister(indexer cache.Indexer) MachineLister {
 
 // List lists all Machines in the indexer.
 func (s *machineLister) List(selector labels.Selector) (ret []*v1alpha1.Machine, err error) {
-	err = cache.ListAll(s.indexer, selector, func(m interface{}) {
+	err = cache.ListAll(s.indexer, selector, func(m any) {
 		ret = append(ret, m.(*v1alpha1.Machine))
 	})
 	return ret, err
@@ -68,7 +68,7 @@ type machineNamespaceLister struct {
 
 // List lists all Machines in the indexer for a given namespace.
 func (s machineNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.Machine, err error) {
-	err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
+	err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m any) {
 		ret = append(ret, m.(*v1alpha1.Machine))
 	})
 	return ret, err
diff --git a/pkg/client/listers/machine/v1alpha1/machineclass.go b/pkg/client/listers/machine/v1alpha1/machineclass.go
index aa8fe540d..46619ecc8 100644
--- a/pkg/client/listers/machine/v1alpha1/machineclass.go
+++ b/pkg/client/listers/machine/v1alpha1/machineclass.go
@@ -36,7 +36,7 @@ func NewMachineClassLister(indexer cache.Indexer) MachineClassLister {
 
 // List lists all MachineClasses in the indexer.
 func (s *machineClassLister) List(selector labels.Selector) (ret []*v1alpha1.MachineClass, err error) {
-	err = cache.ListAll(s.indexer, selector, func(m interface{}) {
+	err = cache.ListAll(s.indexer, selector, func(m any) {
 		ret = append(ret, m.(*v1alpha1.MachineClass))
 	})
 	return ret, err
@@ -68,7 +68,7 @@ type machineClassNamespaceLister struct {
 
 // List lists all MachineClasses in the indexer for a given namespace.
 func (s machineClassNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.MachineClass, err error) {
-	err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
+	err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m any) {
 		ret = append(ret, m.(*v1alpha1.MachineClass))
 	})
 	return ret, err
diff --git a/pkg/client/listers/machine/v1alpha1/machinedeployment.go b/pkg/client/listers/machine/v1alpha1/machinedeployment.go
index 4f79e3c84..4a1f8ff7a 100644
--- a/pkg/client/listers/machine/v1alpha1/machinedeployment.go
+++ b/pkg/client/listers/machine/v1alpha1/machinedeployment.go
@@ -36,7 +36,7 @@ func NewMachineDeploymentLister(indexer cache.Indexer) MachineDeploymentLister {
 
 // List lists all MachineDeployments in the indexer.
 func (s *machineDeploymentLister) List(selector labels.Selector) (ret []*v1alpha1.MachineDeployment, err error) {
-	err = cache.ListAll(s.indexer, selector, func(m interface{}) {
+	err = cache.ListAll(s.indexer, selector, func(m any) {
 		ret = append(ret, m.(*v1alpha1.MachineDeployment))
 	})
 	return ret, err
@@ -68,7 +68,7 @@ type machineDeploymentNamespaceLister struct {
 
 // List lists all MachineDeployments in the indexer for a given namespace.
 func (s machineDeploymentNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.MachineDeployment, err error) {
-	err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
+	err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m any) {
 		ret = append(ret, m.(*v1alpha1.MachineDeployment))
 	})
 	return ret, err
diff --git a/pkg/client/listers/machine/v1alpha1/machineset.go b/pkg/client/listers/machine/v1alpha1/machineset.go
index 824916b6d..bd82e0b8a 100644
--- a/pkg/client/listers/machine/v1alpha1/machineset.go
+++ b/pkg/client/listers/machine/v1alpha1/machineset.go
@@ -36,7 +36,7 @@ func NewMachineSetLister(indexer cache.Indexer) MachineSetLister {
 
 // List lists all MachineSets in the indexer.
 func (s *machineSetLister) List(selector labels.Selector) (ret []*v1alpha1.MachineSet, err error) {
-	err = cache.ListAll(s.indexer, selector, func(m interface{}) {
+	err = cache.ListAll(s.indexer, selector, func(m any) {
 		ret = append(ret, m.(*v1alpha1.MachineSet))
 	})
 	return ret, err
@@ -68,7 +68,7 @@ type machineSetNamespaceLister struct {
 
 // List lists all MachineSets in the indexer for a given namespace.
 func (s machineSetNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.MachineSet, err error) {
-	err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
+	err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m any) {
 		ret = append(ret, m.(*v1alpha1.MachineSet))
 	})
 	return ret, err
diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go
index ccdcfe656..424ede846 100644
--- a/pkg/controller/controller.go
+++ b/pkg/controller/controller.go
@@ -54,18 +54,33 @@ func NewController(
 	autoscalerScaleDownAnnotationDuringRollout bool,
 ) (Controller, error) {
 	controller := &controller{
-		namespace:                      namespace,
-		controlMachineClient:           controlMachineClient,
-		controlCoreClient:              controlCoreClient,
-		targetCoreClient:               targetCoreClient,
-		recorder:                       recorder,
-		expectations:                   NewUIDTrackingContExpectations(NewContExpectations()),
-		nodeQueue:                      workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "node"),
-		machineQueue:                   workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "machine"),
-		machineSetQueue:                workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "machineset"),
-		machineDeploymentQueue:         workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "machinedeployment"),
-		machineSafetyOvershootingQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "machinesafetyovershooting"),
-		safetyOptions:                  safetyOptions,
+		namespace:            namespace,
+		controlMachineClient: controlMachineClient,
+		controlCoreClient:    controlCoreClient,
+		targetCoreClient:     targetCoreClient,
+		recorder:             recorder,
+		expectations:         NewUIDTrackingContExpectations(NewContExpectations()),
+		nodeQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
+			workqueue.DefaultTypedControllerRateLimiter[string](),
+			workqueue.TypedRateLimitingQueueConfig[string]{Name: "node"},
+		),
+		machineQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
+			workqueue.DefaultTypedControllerRateLimiter[string](),
+			workqueue.TypedRateLimitingQueueConfig[string]{Name: "machine"},
+		),
+		machineSetQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
+			workqueue.DefaultTypedControllerRateLimiter[string](),
+			workqueue.TypedRateLimitingQueueConfig[string]{Name: "machineset"},
+		),
+		machineDeploymentQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
+			workqueue.DefaultTypedControllerRateLimiter[string](),
+			workqueue.TypedRateLimitingQueueConfig[string]{Name: "machinedeployment"},
+		),
+		machineSafetyOvershootingQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
+			workqueue.DefaultTypedControllerRateLimiter[string](),
+			workqueue.TypedRateLimitingQueueConfig[string]{Name: "machinesafetyovershooting"},
+		),
+		safetyOptions: safetyOptions,
 		autoscalerScaleDownAnnotationDuringRollout: autoscalerScaleDownAnnotationDuringRollout,
 	}
 
@@ -125,7 +140,7 @@ func NewController(
 	// MachineDeployment Controller Informers
 	_, _ = machineInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
 		UpdateFunc: controller.updateMachineToMachineDeployment,
-		DeleteFunc: controller.deleteMachineDeployment,
+		DeleteFunc: controller.deleteMachineToMachineDeployment,
 	})
 
 	_, _ = machineSetInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
@@ -188,11 +203,11 @@ type controller struct {
 	// target listers – nil when running without a target cluster
 	nodeLister corelisters.NodeLister
 	// queues
-	nodeQueue                      workqueue.RateLimitingInterface
-	machineQueue                   workqueue.RateLimitingInterface
-	machineSetQueue                workqueue.RateLimitingInterface
-	machineDeploymentQueue         workqueue.RateLimitingInterface
-	machineSafetyOvershootingQueue workqueue.RateLimitingInterface
+	nodeQueue                      workqueue.TypedRateLimitingInterface[string]
+	machineQueue                   workqueue.TypedRateLimitingInterface[string]
+	machineSetQueue                workqueue.TypedRateLimitingInterface[string]
+	machineDeploymentQueue         workqueue.TypedRateLimitingInterface[string]
+	machineSafetyOvershootingQueue workqueue.TypedRateLimitingInterface[string]
 	// syncs
 	nodeSynced              cache.InformerSynced
 	machineSynced           cache.InformerSynced
@@ -235,7 +250,7 @@ func (c *controller) Run(workers int, stopCh <-chan struct{}) {
 	// every time when the endpoint is called.
 	prometheus.MustRegister(c)
 
-	for i := 0; i < workers; i++ {
+	for range workers {
 		worker.Run(c.machineSetQueue, "ClusterMachineSet", worker.DefaultMaxRetries, true, c.reconcileClusterMachineSet, stopCh, &waitGroup)
 		worker.Run(c.machineDeploymentQueue, "ClusterMachineDeployment", worker.DefaultMaxRetries, true, c.reconcileClusterMachineDeployment, stopCh, &waitGroup)
 		worker.Run(c.machineSafetyOvershootingQueue, "ClusterMachineSafetyOvershooting", worker.DefaultMaxRetries, true, c.reconcileClusterMachineSafetyOvershooting, stopCh, &waitGroup)
diff --git a/pkg/controller/controller_utils.go b/pkg/controller/controller_utils.go
index 7790fee28..b0e8e8f54 100644
--- a/pkg/controller/controller_utils.go
+++ b/pkg/controller/controller_utils.go
@@ -27,6 +27,7 @@ import (
 	"encoding/binary"
 	"fmt"
 	"hash/fnv"
+	"maps"
 	"strconv"
 	"sync"
 	"sync/atomic"
@@ -131,7 +132,7 @@ func NoResyncPeriodFunc() time.Duration {
 // * Controllers that don't set expectations will get woken up for every matching controllee
 
 // ExpKeyFunc to parse out the key from a ControlleeExpectation
-var ExpKeyFunc = func(obj interface{}) (string, error) {
+var ExpKeyFunc = func(obj any) (string, error) {
 	if e, ok := obj.(*ControlleeExpectations); ok {
 		return e.key, nil
 	}
@@ -299,7 +300,7 @@ func NewContExpectations() *ContExpectations {
 }
 
 // UIDSetKeyFunc to parse out the key from a UIDSet.
-var UIDSetKeyFunc = func(obj interface{}) (string, error) {
+var UIDSetKeyFunc = func(obj any) (string, error) {
 	if u, ok := obj.(*UIDSet); ok {
 		return u.key, nil
 	}
@@ -494,9 +495,7 @@ type MachineControlInterface interface {
 
 func getMachinesLabelSet(template *v1alpha1.MachineTemplateSpec) labels.Set {
 	desiredLabels := make(labels.Set)
-	for k, v := range template.Labels {
-		desiredLabels[k] = v
-	}
+	maps.Copy(desiredLabels, template.Labels)
 	return desiredLabels
 }
 
@@ -508,9 +507,7 @@ func getMachinesFinalizers(template *v1alpha1.MachineTemplateSpec) []string {
 
 func getMachinesAnnotationSet(template *v1alpha1.MachineTemplateSpec, _ runtime.Object) labels.Set {
 	desiredAnnotations := make(labels.Set)
-	for k, v := range template.Annotations {
-		desiredAnnotations[k] = v
-	}
+	maps.Copy(desiredAnnotations, template.Annotations)
 	return desiredAnnotations
 }
 
diff --git a/pkg/controller/deployment.go b/pkg/controller/deployment.go
index fcfc7d663..4e5dd2fef 100644
--- a/pkg/controller/deployment.go
+++ b/pkg/controller/deployment.go
@@ -52,20 +52,20 @@ var controllerKind = v1alpha1.SchemeGroupVersion.WithKind("MachineDeployment")
 // GroupVersionKind is the version kind used to identify objects managed by machine-controller-manager
 var GroupVersionKind = "machine.sapcloud.io/v1alpha1"
 
-func (dc *controller) addMachineDeployment(obj interface{}) {
+func (dc *controller) addMachineDeployment(obj any) {
 	d := obj.(*v1alpha1.MachineDeployment)
 	klog.V(4).Infof("Adding machine deployment %s", d.Name)
 	dc.enqueueMachineDeployment(d)
 }
 
-func (dc *controller) updateMachineDeployment(old, cur interface{}) {
+func (dc *controller) updateMachineDeployment(old, cur any) {
 	oldD := old.(*v1alpha1.MachineDeployment)
 	curD := cur.(*v1alpha1.MachineDeployment)
 	klog.V(4).Infof("Updating machine deployment %s", oldD.Name)
 	dc.enqueueMachineDeployment(curD)
 }
 
-func (dc *controller) deleteMachineDeployment(obj interface{}) {
+func (dc *controller) deleteMachineDeployment(obj any) {
 	d, ok := obj.(*v1alpha1.MachineDeployment)
 	if !ok {
 		tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
@@ -75,7 +75,7 @@ func (dc *controller) deleteMachineDeployment(obj interface{}) {
 		}
 		d, ok = tombstone.Obj.(*v1alpha1.MachineDeployment)
 		if !ok {
-			utilruntime.HandleError(fmt.Errorf("Tombstone contained object that is not a Machine Deployment %#v", obj))
+			utilruntime.HandleError(fmt.Errorf("tombstone contained object that is not a MachineDeployment %#v", obj))
 			return
 		}
 	}
@@ -84,7 +84,7 @@ func (dc *controller) deleteMachineDeployment(obj interface{}) {
 }
 
 // addMachineSet enqueues the deployment that manages a MachineSet when the MachineSet is created.
-func (dc *controller) addMachineSetToDeployment(obj interface{}) {
+func (dc *controller) addMachineSetToDeployment(obj any) {
 	is := obj.(*v1alpha1.MachineSet)
 
 	if is.DeletionTimestamp != nil {
@@ -141,7 +141,7 @@ func (dc *controller) getMachineDeploymentsForMachineSet(machineSet *v1alpha1.Ma
 // is updated and wake them up. If the anything of the MachineSets have changed, we need to
 // awaken both the old and new deployments. old and cur must be *extensions.MachineSet
 // types.
-func (dc *controller) updateMachineSetToDeployment(old, cur interface{}) {
+func (dc *controller) updateMachineSetToDeployment(old, cur any) {
 	curMachineSet := cur.(*v1alpha1.MachineSet)
 	oldMachineSet := old.(*v1alpha1.MachineSet)
 	if curMachineSet.ResourceVersion == oldMachineSet.ResourceVersion {
@@ -189,7 +189,7 @@ func (dc *controller) updateMachineSetToDeployment(old, cur interface{}) {
 // deleteMachineSet enqueues the deployment that manages a MachineSet when
 // the MachineSet is deleted. obj could be an *v1alpha1.MachineSet, or
 // a DeletionFinalStateUnknown marker item.
-func (dc *controller) deleteMachineSetToDeployment(obj interface{}) {
+func (dc *controller) deleteMachineSetToDeployment(obj any) {
 	machineSet, ok := obj.(*v1alpha1.MachineSet)
 
 	// When a delete is dropped, the relist will notice a Machine in the store not
@@ -199,12 +199,12 @@ func (dc *controller) deleteMachineSetToDeployment(obj interface{}) {
 	if !ok {
 		tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
 		if !ok {
-			utilruntime.HandleError(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
+			utilruntime.HandleError(fmt.Errorf("couldn't get object from tombstone %#v", obj))
 			return
 		}
 		machineSet, ok = tombstone.Obj.(*v1alpha1.MachineSet)
 		if !ok {
-			utilruntime.HandleError(fmt.Errorf("Tombstone contained object that is not a MachineSet %#v", obj))
+			utilruntime.HandleError(fmt.Errorf("tombstone contained object that is not a MachineSet %#v", obj))
 			return
 		}
 	}
@@ -249,7 +249,8 @@ func (dc *controller) updateMachineToMachineDeployment(old, cur any) {
 }
 
 // deleteMachine will enqueue a Recreate Deployment once all of its Machines have stopped running.
-func (dc *controller) deleteMachineToMachineDeployment(ctx context.Context, obj interface{}) {
+func (dc *controller) deleteMachineToMachineDeployment(obj any) {
+	ctx := context.Background()
 	machine, ok := obj.(*v1alpha1.Machine)
 
 	// When a delete is dropped, the relist will notice a Machine in the store not
@@ -259,12 +260,12 @@ func (dc *controller) deleteMachineToMachineDeployment(ctx context.Context, obj
 	if !ok {
 		tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
 		if !ok {
-			utilruntime.HandleError(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
+			utilruntime.HandleError(fmt.Errorf("couldn't get object from tombstone %#v", obj))
 			return
 		}
 		machine, ok = tombstone.Obj.(*v1alpha1.Machine)
 		if !ok {
-			utilruntime.HandleError(fmt.Errorf("Tombstone contained object that is not a machine %#v", obj))
+			utilruntime.HandleError(fmt.Errorf("tombstone contained object that is not a machine %#v", obj))
 			return
 		}
 	}
@@ -292,7 +293,7 @@ func (dc *controller) deleteMachineToMachineDeployment(ctx context.Context, obj
 func (dc *controller) enqueueMachineDeployment(deployment *v1alpha1.MachineDeployment) {
 	key, err := KeyFunc(deployment)
 	if err != nil {
-		utilruntime.HandleError(fmt.Errorf("Couldn't get key for object %#v: %v", deployment, err))
+		utilruntime.HandleError(fmt.Errorf("couldn't get key for object %#v: %v", deployment, err))
 		return
 	}
 
@@ -302,7 +303,7 @@ func (dc *controller) enqueueMachineDeployment(deployment *v1alpha1.MachineDeplo
 func (dc *controller) enqueueRateLimited(deployment *v1alpha1.MachineDeployment) {
 	key, err := KeyFunc(deployment)
 	if err != nil {
-		utilruntime.HandleError(fmt.Errorf("Couldn't get key for object %#v: %v", deployment, err))
+		utilruntime.HandleError(fmt.Errorf("couldn't get key for object %#v: %v", deployment, err))
 		return
 	}
 
@@ -313,7 +314,7 @@ func (dc *controller) enqueueRateLimited(deployment *v1alpha1.MachineDeployment)
 func (dc *controller) enqueueMachineDeploymentAfter(deployment *v1alpha1.MachineDeployment, after time.Duration) {
 	key, err := KeyFunc(deployment)
 	if err != nil {
-		utilruntime.HandleError(fmt.Errorf("Couldn't get key for object %#v: %v", deployment, err))
+		utilruntime.HandleError(fmt.Errorf("couldn't get key for object %#v: %v", deployment, err))
 		return
 	}
 
diff --git a/pkg/controller/deployment_rollback.go b/pkg/controller/deployment_rollback.go
index 85c82097b..beb7e45b8 100644
--- a/pkg/controller/deployment_rollback.go
+++ b/pkg/controller/deployment_rollback.go
@@ -25,13 +25,9 @@ package controller
 import (
 	"context"
 	"fmt"
-	"time"
-
 	"github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1"
-	"github.com/gardener/machine-controller-manager/pkg/util/nodeops"
 	v1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/labels"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/klog/v2"
 )
@@ -64,17 +60,17 @@ func (dc *controller) rollback(ctx context.Context, d *v1alpha1.MachineDeploymen
 			klog.V(4).Infof("Found machine set %q with desired revision %d", is.Name, v)
 
 			// Remove PreferNoSchedule taints from nodes which were backing the machineSet
-			err = dc.removeTaintNodesBackingMachineSet(
-				ctx,
-				is,
-				&v1.Taint{
+			if _, exists := is.Annotations[PreferNoScheduleKey]; exists {
+				taint := &v1.Taint{
 					Key:    PreferNoScheduleKey,
 					Value:  "True",
 					Effect: "PreferNoSchedule",
-				},
-			)
-			if err != nil {
-				klog.Warningf("Failed to remove taints %s off nodes. Error: %s", PreferNoScheduleKey, err)
+				}
+
+				if err := dc.removeTaintNodesBackingMachineSet(ctx, is, taint); err != nil {
+					klog.Errorf("Failed to remove taints %s from all nodes. Error: %v", PreferNoScheduleKey, err)
+					return err
+				}
 			}
 
 			// rollback by copying podTemplate.Spec from the machine set
@@ -139,93 +135,3 @@ func (dc *controller) updateMachineDeploymentAndClearRollbackTo(ctx context.Cont
 	_, err := dc.controlMachineClient.MachineDeployments(d.Namespace).Update(ctx, d, metav1.UpdateOptions{})
 	return err
 }
-
-// removeTaintNodesBackingMachineSet removes taints from all nodes backing the machineSets
-func (dc *controller) removeTaintNodesBackingMachineSet(ctx context.Context, machineSet *v1alpha1.MachineSet, taint *v1.Taint) error {
-
-	if _, exists := machineSet.Annotations[taint.Key]; !exists {
-		// No taint exists
-		klog.Warningf("No taint exists on machineSet: %s. Hence not removing.", machineSet.Name)
-		return nil
-	}
-
-	klog.V(2).Infof("Trying to untaint MachineSet object %q with %s to enable scheduling of pods", machineSet.Name, taint.Key)
-	selector, err := metav1.LabelSelectorAsSelector(machineSet.Spec.Selector)
-	if err != nil {
-		return err
-	}
-
-	// list all machines to include the machines that don't match the ms`s selector
-	// anymore but has the stale controller ref.
-	// TODO: Do the List and Filter in a single pass, or use an index.
-	filteredMachines, err := dc.machineLister.List(labels.Everything())
-	if err != nil {
-		return err
-	}
-	// NOTE: filteredMachines are pointing to objects from cache - if you need to
-	// modify them, you need to copy it first.
-	filteredMachines, err = dc.claimMachines(ctx, machineSet, selector, filteredMachines)
-	if err != nil {
-		return err
-	}
-
-	// Iterate through all machines and remove the PreferNoSchedule taint
-	// to avoid scheduling on older machines
-	for _, machine := range filteredMachines {
-		if machine.Labels[v1alpha1.NodeLabelKey] != "" {
-			node, err := dc.targetCoreClient.CoreV1().Nodes().Get(ctx, machine.Labels[v1alpha1.NodeLabelKey], metav1.GetOptions{})
-			if err != nil {
-				klog.Warningf("Node taint removal failed for node: %s, Error: %s", machine.Labels[v1alpha1.NodeLabelKey], err)
-				continue
-			}
-			if err := nodeops.RemoveTaintOffNode(
-				ctx,
-				dc.targetCoreClient,
-				machine.Labels[v1alpha1.NodeLabelKey],
-				node,
-				taint,
-			); err != nil {
-				klog.Warningf("Node taint removal failed for node: %s, Error: %s", machine.Labels[v1alpha1.NodeLabelKey], err)
-			}
-		}
-	}
-
-	retryDeadline := time.Now().Add(maxRetryDeadline)
-	for {
-		machineSet, err = dc.controlMachineClient.MachineSets(machineSet.Namespace).Get(ctx, machineSet.Name, metav1.GetOptions{})
-		if err != nil {
-			if time.Now().Before(retryDeadline) {
-				klog.Warningf("Unable to fetch MachineSet object %s, Error: %+v", machineSet.Name, err)
-				time.Sleep(conflictRetryInterval)
-				continue
-			} else {
-				// Timeout occurred
-				klog.Errorf("Timeout occurred: Unable to fetch MachineSet object %s, Error: %+v", machineSet.Name, err)
-				return err
-			}
-		}
-
-		msCopy := machineSet.DeepCopy()
-		delete(msCopy.Annotations, taint.Key)
-
-		machineSet, err = dc.controlMachineClient.MachineSets(msCopy.Namespace).Update(ctx, msCopy, metav1.UpdateOptions{})
-
-		if err != nil {
-			if time.Now().Before(retryDeadline) {
-				klog.Warningf("Unable to update MachineSet object %s, Error: %+v", machineSet.Name, err)
-				time.Sleep(conflictRetryInterval)
-				continue
-			} else {
-				// Timeout occurred
-				klog.Errorf("Timeout occurred: Unable to update MachineSet object %s, Error: %+v", machineSet.Name, err)
-				return err
-			}
-		}
-
-		// Break out of loop when update succeeds
-		break
-	}
-	klog.V(2).Infof("Removed taint %s from MachineSet object %q", taint.Key, machineSet.Name)
-
-	return nil
-}
diff --git a/pkg/controller/deployment_rolling.go b/pkg/controller/deployment_rolling.go
index 02ac533c4..033be6c31 100644
--- a/pkg/controller/deployment_rolling.go
+++ b/pkg/controller/deployment_rolling.go
@@ -115,6 +115,20 @@ func (dc *controller) rolloutRolling(ctx context.Context, d *v1alpha1.MachineDep
 				return err
 			}
 		}
+		// This check is needed because sometimes we can backtrack on a deployment, and this taint can stick
+		// See https://github.com/gardener/machine-controller-manager/issues/989 for more details
+		if _, ok := newIS.Annotations[PreferNoScheduleKey]; ok {
+			taint := &v1.Taint{
+				Key:    PreferNoScheduleKey,
+				Value:  "True",
+				Effect: "PreferNoSchedule",
+			}
+
+			if err := dc.removeTaintNodesBackingMachineSet(ctx, newIS, taint); err != nil {
+				klog.Errorf("Failed to remove taints %s from nodes. Error: %v", PreferNoScheduleKey, err)
+				return err
+			}
+		}
 		if err := dc.cleanupMachineDeployment(ctx, oldISs, d); err != nil {
 			return err
 		}
diff --git a/pkg/controller/deployment_sync.go b/pkg/controller/deployment_sync.go
index 7558e1f7e..b0f13d440 100644
--- a/pkg/controller/deployment_sync.go
+++ b/pkg/controller/deployment_sync.go
@@ -184,7 +184,7 @@ func (dc *controller) addHashKeyToISAndMachines(ctx context.Context, is *v1alpha
 	if updatedIS.Generation > updatedIS.Status.ObservedGeneration {
 		// TODO: Revisit if we really need to wait here as opposed to returning and
 		// potentially unblocking this worker (can wait up to 1min before timing out).
-		if err = WaitForMachineSetUpdated(dc.machineSetLister, updatedIS.Generation, updatedIS.Namespace, updatedIS.Name); err != nil {
+		if err = WaitForMachineSetUpdated(ctx, dc.machineSetLister, updatedIS.Generation, updatedIS.Namespace, updatedIS.Name); err != nil {
 			return nil, fmt.Errorf("error waiting for machine set %s to be observed by controller: %v", updatedIS.Name, err)
 		}
 		klog.V(4).Infof("Observed the update of machine set %s's machine template with hash %s.", is.Name, hash)
@@ -202,7 +202,7 @@ func (dc *controller) addHashKeyToISAndMachines(ctx context.Context, is *v1alpha
 	// back to the number of replicas in the spec.
 	// TODO: Revisit if we really need to wait here as opposed to returning and
 	// potentially unblocking this worker (can wait up to 1min before timing out).
-	if err := WaitForMachinesHashPopulated(dc.machineSetLister, updatedIS.Generation, updatedIS.Namespace, updatedIS.Name); err != nil {
+	if err := WaitForMachinesHashPopulated(ctx, dc.machineSetLister, updatedIS.Generation, updatedIS.Namespace, updatedIS.Name); err != nil {
 		return nil, fmt.Errorf("Machine set %s: error waiting for machineset controller to observe machines being labeled with template hash: %v", updatedIS.Name, err)
 	}
 
@@ -470,10 +470,7 @@ func (dc *controller) scale(ctx context.Context, deployment *v1alpha1.MachineDep
 			// Incorporate any leftovers to the largest machine set.
 			if i == 0 && deploymentReplicasToAdd != 0 {
 				leftover := deploymentReplicasToAdd - deploymentReplicasAdded
-				nameToSize[is.Name] = nameToSize[is.Name] + leftover
-				if nameToSize[is.Name] < 0 {
-					nameToSize[is.Name] = 0
-				}
+				nameToSize[is.Name] = max(nameToSize[is.Name]+leftover, 0)
 				klog.V(3).Infof("leftover proportion increase of %d done in largest machineSet %s", leftover, is.Name)
 			}
 
@@ -586,7 +583,7 @@ func (dc *controller) cleanupMachineDeployment(ctx context.Context, oldISs []*v1
 	sort.Sort(MachineSetsByCreationTimestamp(cleanableISes))
 	klog.V(4).Infof("Looking to cleanup old machine sets for deployment %q", deployment.Name)
 
-	for i := int32(0); i < diff; i++ {
+	for i := range diff {
 		is := cleanableISes[i]
 		// Avoid delete machine set with non-zero replica counts
 		if is.Status.Replicas != 0 || (is.Spec.Replicas) != 0 || is.Generation > is.Status.ObservedGeneration || is.DeletionTimestamp != nil {
@@ -621,12 +618,9 @@ func (dc *controller) syncMachineDeploymentStatus(ctx context.Context, allISs []
 func calculateDeploymentStatus(allISs []*v1alpha1.MachineSet, newIS *v1alpha1.MachineSet, deployment *v1alpha1.MachineDeployment) v1alpha1.MachineDeploymentStatus {
 	availableReplicas := GetAvailableReplicaCountForMachineSets(allISs)
 	totalReplicas := GetReplicaCountForMachineSets(allISs)
-	unavailableReplicas := totalReplicas - availableReplicas
 	// If unavailableReplicas is negative, then that means the Deployment has more available replicas running than
 	// desired, e.g. whenever it scales down. In such a case we should simply default unavailableReplicas to zero.
-	if unavailableReplicas < 0 {
-		unavailableReplicas = 0
-	}
+	unavailableReplicas := max(totalReplicas-availableReplicas, 0)
 
 	status := v1alpha1.MachineDeploymentStatus{
 		// TODO: Ensure that if we start retrying status updates, we won't pick up a new Generation value.
diff --git a/pkg/controller/deployment_util.go b/pkg/controller/deployment_util.go
index 3dbce3ca1..690b4feb1 100644
--- a/pkg/controller/deployment_util.go
+++ b/pkg/controller/deployment_util.go
@@ -25,6 +25,7 @@ package controller
 import (
 	"context"
 	"fmt"
+	"github.com/gardener/machine-controller-manager/pkg/util/nodeops"
 	"maps"
 	"reflect"
 	"sort"
@@ -59,7 +60,7 @@ type MachineDeploymentListerExpansion interface {
 }
 
 // MachineDeploymentNamespaceListerExpansion allows custom methods to be added to MachineDeploymentNamespaceLister.
-type MachineDeploymentNamespaceListerExpansion interface{}
+type MachineDeploymentNamespaceListerExpansion any
 
 // GetMachineDeploymentsForMachineSet returns a list of Deployments that potentially
 // match a MachineSet. Only the one specified in the MachineSet's ControllerRef
@@ -937,8 +938,8 @@ func FindOldMachineSets(deployment *v1alpha1.MachineDeployment, isList []*v1alph
 }
 
 // WaitForMachineSetUpdated polls the machine set until it is updated.
-func WaitForMachineSetUpdated(c v1alpha1listers.MachineSetLister, desiredGeneration int64, namespace, name string) error {
-	return wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) {
+func WaitForMachineSetUpdated(ctx context.Context, c v1alpha1listers.MachineSetLister, desiredGeneration int64, namespace, name string) error {
+	return wait.PollUntilContextTimeout(ctx, 1*time.Second, 1*time.Minute, true, func(_ context.Context) (bool, error) {
 		is, err := c.MachineSets(namespace).Get(name)
 		if err != nil {
 			return false, err
@@ -948,8 +949,8 @@ func WaitForMachineSetUpdated(c v1alpha1listers.MachineSetLister, desiredGenerat
 }
 
 // WaitForMachinesHashPopulated polls the machine set until updated and fully labeled.
-func WaitForMachinesHashPopulated(c v1alpha1listers.MachineSetLister, desiredGeneration int64, namespace, name string) error {
-	return wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) {
+func WaitForMachinesHashPopulated(ctx context.Context, c v1alpha1listers.MachineSetLister, desiredGeneration int64, namespace, name string) error {
+	return wait.PollUntilContextTimeout(ctx, 1*time.Second, 1*time.Minute, true, func(_ context.Context) (bool, error) {
 		is, err := c.MachineSets(namespace).Get(name)
 		if err != nil {
 			return false, err
@@ -1202,11 +1203,101 @@ func IsSaturated(deployment *v1alpha1.MachineDeployment, is *v1alpha1.MachineSet
 		is.Status.AvailableReplicas == (deployment.Spec.Replicas)
 }
 
+// removeTaintNodesBackingMachineSet removes taints from all nodes backing the machineSets
+func (dc *controller) removeTaintNodesBackingMachineSet(ctx context.Context, machineSet *v1alpha1.MachineSet, taint *v1.Taint) error {
+
+	if _, exists := machineSet.Annotations[taint.Key]; !exists {
+		// No taint exists
+		klog.Warningf("No taint exists on machineSet: %s. Hence not removing.", machineSet.Name)
+		return nil
+	}
+
+	klog.V(2).Infof("Trying to untaint MachineSet object %q with %s to enable scheduling of pods", machineSet.Name, taint.Key)
+	selector, err := metav1.LabelSelectorAsSelector(machineSet.Spec.Selector)
+	if err != nil {
+		return err
+	}
+
+	// list all machines to include the machines that don't match the ms`s selector
+	// anymore but has the stale controller ref.
+	// TODO: Do the List and Filter in a single pass, or use an index.
+	filteredMachines, err := dc.machineLister.List(labels.Everything())
+	if err != nil {
+		return err
+	}
+	// NOTE: filteredMachines are pointing to objects from cache - if you need to
+	// modify them, you need to copy it first.
+	filteredMachines, err = dc.claimMachines(ctx, machineSet, selector, filteredMachines)
+	if err != nil {
+		return err
+	}
+
+	// Iterate through all machines and remove the PreferNoSchedule taint
+	// to avoid scheduling on older machines
+	for _, machine := range filteredMachines {
+		if machine.Labels[v1alpha1.NodeLabelKey] != "" {
+			node, err := dc.targetCoreClient.CoreV1().Nodes().Get(ctx, machine.Labels[v1alpha1.NodeLabelKey], metav1.GetOptions{})
+			if err != nil {
+				klog.Warningf("Node taint removal failed for node: %s, Error: %s", machine.Labels[v1alpha1.NodeLabelKey], err)
+				continue
+			}
+			if err := nodeops.RemoveTaintOffNode(
+				ctx,
+				dc.targetCoreClient,
+				machine.Labels[v1alpha1.NodeLabelKey],
+				node,
+				taint,
+			); err != nil {
+				klog.Warningf("Node taint removal failed for node: %s, Error: %s", machine.Labels[v1alpha1.NodeLabelKey], err)
+			}
+		}
+	}
+
+	retryDeadline := time.Now().Add(maxRetryDeadline)
+	for {
+		machineSet, err = dc.controlMachineClient.MachineSets(machineSet.Namespace).Get(ctx, machineSet.Name, metav1.GetOptions{})
+		if err != nil {
+			if time.Now().Before(retryDeadline) {
+				klog.Warningf("Unable to fetch MachineSet object %s, Error: %+v", machineSet.Name, err)
+				time.Sleep(conflictRetryInterval)
+				continue
+			} else {
+				// Timeout occurred
+				klog.Errorf("Timeout occurred: Unable to fetch MachineSet object %s, Error: %+v", machineSet.Name, err)
+				return err
+			}
+		}
+
+		msCopy := machineSet.DeepCopy()
+		delete(msCopy.Annotations, taint.Key)
+
+		machineSet, err = dc.controlMachineClient.MachineSets(msCopy.Namespace).Update(ctx, msCopy, metav1.UpdateOptions{})
+
+		if err != nil {
+			if time.Now().Before(retryDeadline) {
+				klog.Warningf("Unable to update MachineSet object %s, Error: %+v", machineSet.Name, err)
+				time.Sleep(conflictRetryInterval)
+				continue
+			} else {
+				// Timeout occurred
+				klog.Errorf("Timeout occurred: Unable to update MachineSet object %s, Error: %+v", machineSet.Name, err)
+				return err
+			}
+		}
+
+		// Break out of loop when update succeeds
+		break
+	}
+	klog.V(2).Infof("Removed taint %s from MachineSet object %q", taint.Key, machineSet.Name)
+
+	return nil
+}
+
 // WaitForObservedMachineDeployment polls for deployment to be updated so that deployment.Status.ObservedGeneration >= desiredGeneration.
 // Returns error if polling timesout.
 func WaitForObservedMachineDeployment(getDeploymentFunc func() (*v1alpha1.MachineDeployment, error), desiredGeneration int64, interval, timeout time.Duration) error {
 	// TODO: This should take clientset.Interface when all code is updated to use clientset. Keeping it this way allows the function to be used by callers who have client.Interface.
-	return wait.PollImmediate(interval, timeout, func() (bool, error) {
+	return wait.PollUntilContextTimeout(context.Background(), interval, timeout, true, func(_ context.Context) (bool, error) {
 		deployment, err := getDeploymentFunc()
 		if err != nil {
 			return false, err
@@ -1219,7 +1310,7 @@ func WaitForObservedMachineDeployment(getDeploymentFunc func() (*v1alpha1.Machin
 // Returns error if polling timesout.
 // TODO: remove the duplicate
 func WaitForObservedDeploymentInternal(getDeploymentFunc func() (*v1alpha1.MachineDeployment, error), desiredGeneration int64, interval, timeout time.Duration) error {
-	return wait.Poll(interval, timeout, func() (bool, error) {
+	return wait.PollUntilContextTimeout(context.Background(), interval, timeout, false, func(_ context.Context) (bool, error) {
 		deployment, err := getDeploymentFunc()
 		if err != nil {
 			return false, err
diff --git a/pkg/controller/machine_safety.go b/pkg/controller/machine_safety.go
index 2ac152c22..de09e5d73 100644
--- a/pkg/controller/machine_safety.go
+++ b/pkg/controller/machine_safety.go
@@ -285,13 +285,13 @@ func (c *controller) checkAndFreezeORUnfreezeMachineSets(ctx context.Context) er
 }
 
 // addMachineToSafetyOvershooting enqueues into machineSafetyOvershootingQueue when a new machine is added
-func (c *controller) addMachineToSafetyOvershooting(obj interface{}) {
+func (c *controller) addMachineToSafetyOvershooting(obj any) {
 	machine := obj.(*v1alpha1.Machine)
 	c.enqueueMachineSafetyOvershootingKey(machine)
 }
 
 // enqueueMachineSafetyOvershootingKey enqueues into machineSafetyOvershootingQueue
-func (c *controller) enqueueMachineSafetyOvershootingKey(_ interface{}) {
+func (c *controller) enqueueMachineSafetyOvershootingKey(_ any) {
 	c.machineSafetyOvershootingQueue.Add("")
 }
 
diff --git a/pkg/controller/machineset.go b/pkg/controller/machineset.go
index 536d47cc8..6a5701e3e 100644
--- a/pkg/controller/machineset.go
+++ b/pkg/controller/machineset.go
@@ -134,7 +134,7 @@ func (c *controller) resolveMachineSetControllerRef(namespace string, controller
 }
 
 // callback when MachineSet is updated
-func (c *controller) machineSetUpdate(old, cur interface{}) {
+func (c *controller) machineSetUpdate(old, cur any) {
 	oldMachineSet := old.(*v1alpha1.MachineSet)
 	currentMachineSet := cur.(*v1alpha1.MachineSet)
 
@@ -157,7 +157,7 @@ func (c *controller) machineSetUpdate(old, cur interface{}) {
 }
 
 // When a machine is created, enqueue the machine set that manages it and update its expectations.
-func (c *controller) addMachineToMachineSet(obj interface{}) {
+func (c *controller) addMachineToMachineSet(obj any) {
 	machine := obj.(*v1alpha1.Machine)
 
 	if machine.DeletionTimestamp != nil {
@@ -203,7 +203,7 @@ func (c *controller) addMachineToMachineSet(obj interface{}) {
 // When a machine is updated, figure out what machine set/s manage it and wake them
 // up. If the labels of the machine have changed we need to awaken both the old
 // and new machine set. old and cur must be *v1alpha1.Machine types.
-func (c *controller) updateMachineToMachineSet(old, cur interface{}) {
+func (c *controller) updateMachineToMachineSet(old, cur any) {
 	curMachine := cur.(*v1alpha1.Machine)
 	oldMachine := old.(*v1alpha1.Machine)
 	if curMachine.ResourceVersion == oldMachine.ResourceVersion {
@@ -267,7 +267,7 @@ func (c *controller) updateMachineToMachineSet(old, cur interface{}) {
 
 // When a machine is deleted, enqueue the machine set that manages the machine and update its expectations.
 // obj could be an *v1alpha1.Machine, or a DeletionFinalStateUnknown marker item.
-func (c *controller) deleteMachineToMachineSet(obj interface{}) {
+func (c *controller) deleteMachineToMachineSet(obj any) {
 	machine, ok := obj.(*v1alpha1.Machine)
 
 	// When a delete is dropped, the relist will notice a machine in the store not
@@ -306,7 +306,7 @@ func (c *controller) deleteMachineToMachineSet(obj interface{}) {
 }
 
 // obj could be an *extensions.MachineSet, or a DeletionFinalStateUnknown marker item.
-func (c *controller) enqueueMachineSet(obj interface{}) {
+func (c *controller) enqueueMachineSet(obj any) {
 	key, err := KeyFunc(obj)
 	if err != nil {
 		utilruntime.HandleError(fmt.Errorf("couldn't get key for object %+v: %v", obj, err))
@@ -316,7 +316,7 @@ func (c *controller) enqueueMachineSet(obj interface{}) {
 }
 
 // obj could be an *extensions.MachineSet, or a DeletionFinalStateUnknown marker item.
-func (c *controller) enqueueMachineSetAfter(obj interface{}, after time.Duration) {
+func (c *controller) enqueueMachineSetAfter(obj any, after time.Duration) {
 	key, err := KeyFunc(obj)
 	if err != nil {
 		utilruntime.HandleError(fmt.Errorf("couldn't get key for object %+v: %v", obj, err))
@@ -445,7 +445,7 @@ func (c *controller) manageReplicas(ctx context.Context, allMachines []*v1alpha1
 		// retry the slow start process.
 		if skippedMachines := diff - successfulCreations; skippedMachines > 0 {
 			klog.V(2).Infof("Slow-start failure. Skipping creation of %d machines, decrementing expectations for %v %v/%v", skippedMachines, machineSet.Kind, machineSet.Namespace, machineSet.Name)
-			for i := 0; i < skippedMachines; i++ {
+			for range skippedMachines {
 				// Decrement the expected number of creates because the informer won't observe this machine
 				c.expectations.CreationObserved(machineSetKey)
 			}
@@ -702,7 +702,7 @@ func (c *controller) prepareMachineForDeletion(ctx context.Context, targetMachin
 
 	machineSetKey, err := KeyFunc(machineSet)
 	if err != nil {
-		utilruntime.HandleError(fmt.Errorf("Couldn't get key for %v %#v: %v", machineSet.Kind, machineSet, err))
+		utilruntime.HandleError(fmt.Errorf("couldn't get key for %v %#v: %v", machineSet.Kind, machineSet, err))
 		return
 	}
 
@@ -801,7 +801,7 @@ func (c *controller) updateMachineSetFinalizers(ctx context.Context, machineSet
 	var err error
 
 	// Stop retrying if we exceed finalizerUpdateRetries - the machineSet will be requeued with rate limit
-	for i := 0; i < finalizerUpdateRetries; i++ {
+	for range finalizerUpdateRetries {
 		// Get the latest version of the machineSet so that we can avoid conflicts
 		machineSet, err = c.controlMachineClient.MachineSets(machineSet.Namespace).Get(ctx, machineSet.Name, metav1.GetOptions{})
 		if err != nil {
diff --git a/pkg/util/configz/configz.go b/pkg/util/configz/configz.go
index 48b96f3c9..5911d03e0 100644
--- a/pkg/util/configz/configz.go
+++ b/pkg/util/configz/configz.go
@@ -36,7 +36,7 @@ var (
 
 // Config is the utility used to configure
 type Config struct {
-	val interface{}
+	val any
 }
 
 // InstallHandler used to handle /configz endpoint
@@ -68,7 +68,7 @@ func Delete(name string) {
 }
 
 // Set set's up the config
-func (v *Config) Set(val interface{}) {
+func (v *Config) Set(val any) {
 	configsGuard.Lock()
 	defer configsGuard.Unlock()
 	v.val = val
diff --git a/pkg/util/hash/hash.go b/pkg/util/hash/hash.go
index e84eb6664..f895070fe 100644
--- a/pkg/util/hash/hash.go
+++ b/pkg/util/hash/hash.go
@@ -31,7 +31,7 @@ import (
 // DeepHashObject writes specified object to hash using the spew library
 // which follows pointers and prints actual values of the nested objects
 // ensuring the hash does not change when a pointer changes.
-func DeepHashObject(hasher hash.Hash, objectToWrite interface{}) {
+func DeepHashObject(hasher hash.Hash, objectToWrite any) {
 	hasher.Reset()
 	printer := spew.ConfigState{
 		Indent:         " ",
diff --git a/pkg/util/labels/labels.go b/pkg/util/labels/labels.go
index 7251b23c6..350d70ac3 100644
--- a/pkg/util/labels/labels.go
+++ b/pkg/util/labels/labels.go
@@ -24,6 +24,7 @@ package labels
 import (
 	"encoding/json"
 	"fmt"
+	"maps"
 
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
@@ -37,9 +38,7 @@ func CloneAndAddLabel(labels map[string]string, labelKey, labelValue string) map
 	}
 	// Clone.
 	newLabels := map[string]string{}
-	for key, value := range labels {
-		newLabels[key] = value
-	}
+	maps.Copy(newLabels, labels)
 	newLabels[labelKey] = labelValue
 	return newLabels
 }
@@ -53,9 +52,7 @@ func CloneAndRemoveLabel(labels map[string]string, labelKey string) map[string]s
 	}
 	// Clone.
 	newLabels := map[string]string{}
-	for key, value := range labels {
-		newLabels[key] = value
-	}
+	maps.Copy(newLabels, labels)
 	delete(newLabels, labelKey)
 	return newLabels
 }
@@ -87,9 +84,7 @@ func CloneSelectorAndAddLabel(selector *metav1.LabelSelector, labelKey, labelVal
 	// TODO(madhusudancs): Check if you can use deepCopy_extensions_LabelSelector here.
 	newSelector.MatchLabels = make(map[string]string)
 	if selector.MatchLabels != nil {
-		for key, val := range selector.MatchLabels {
-			newSelector.MatchLabels[key] = val
-		}
+		maps.Copy(newSelector.MatchLabels, selector.MatchLabels)
 	}
 	newSelector.MatchLabels[labelKey] = labelValue
 
diff --git a/pkg/util/permits/permits.go b/pkg/util/permits/permits.go
index 960478b0f..a250087a4 100644
--- a/pkg/util/permits/permits.go
+++ b/pkg/util/permits/permits.go
@@ -156,7 +156,7 @@ func (pg *permitGiver) isPermitAcquired(key string) bool {
 }
 
 func (pg *permitGiver) cleanupStalePermitEntries(stalePermitKeyTimeout time.Duration) {
-	pg.keyPermitsMap.Range(func(key, value interface{}) bool {
+	pg.keyPermitsMap.Range(func(key, value any) bool {
 		p := value.(permit)
 		timeout := time.Now().Add(-stalePermitKeyTimeout).Sub(p.lastAcquiredPermitTime)
 		if timeout > 0 && len(p.c) == 0 {
@@ -169,7 +169,7 @@ func (pg *permitGiver) cleanupStalePermitEntries(stalePermitKeyTimeout time.Dura
 func (pg *permitGiver) Close() {
 	close(pg.stopC)
 	// close all permit channels
-	pg.keyPermitsMap.Range(func(_, value interface{}) bool {
+	pg.keyPermitsMap.Range(func(_, value any) bool {
 		p := value.(permit)
 		close(p.c)
 		return true
diff --git a/pkg/util/provider/app/app.go b/pkg/util/provider/app/app.go
index 5f4446722..054976f9c 100644
--- a/pkg/util/provider/app/app.go
+++ b/pkg/util/provider/app/app.go
@@ -324,7 +324,8 @@ func getAvailableResources(clientBuilder coreclientbuilder.ClientBuilder) (map[s
 	var healthzContent string
 	// If apiserver is not running we should wait for some time and fail only then. This is particularly
 	// important when we start apiserver and controller manager at the same time.
-	err := wait.PollImmediate(time.Second, 10*time.Second, func() (bool, error) {
+	immediatePoll := true
+	err := wait.PollUntilContextTimeout(context.Background(), time.Second, 10*time.Second, immediatePoll, func(context.Context) (bool, error) {
 		client, err := clientBuilder.Client("controller-discovery")
 		if err != nil {
 			klog.Errorf("Failed to get api versions from server: %v", err)
diff --git a/pkg/util/provider/drain/drain.go b/pkg/util/provider/drain/drain.go
index dee9a1bc4..2dba1a196 100644
--- a/pkg/util/provider/drain/drain.go
+++ b/pkg/util/provider/drain/drain.go
@@ -641,7 +641,7 @@ func (o *Options) evictPodsWithPv(ctx context.Context, attemptEvict bool, pods [
 	)
 
 	if attemptEvict {
-		for i := 0; i < nretries; i++ {
+		for range nretries {
 			remainingPods, fastTrack = o.evictPodsWithPVInternal(ctx, attemptEvict, pods, podVolumeInfoMap, policyGroupVersion, getPodFn, returnCh)
 			if fastTrack || len(remainingPods) == 0 {
 				// Either all pods got evicted or we need to fast track the return (node deletion detected)
@@ -1095,7 +1095,7 @@ func (o *Options) evictPodWithoutPVInternal(ctx context.Context, attemptEvict bo
 	}
 
 	bufferPeriod := 30 * time.Second
-	podArray, err = o.waitForDelete(podArray, Interval, timeout+bufferPeriod, getPodFn)
+	podArray, err = o.waitForDelete(ctx, podArray, Interval, timeout+bufferPeriod, getPodFn)
 	if err == nil {
 		if len(podArray) > 0 {
 			returnCh <- fmt.Errorf("timeout expired while waiting for pod %q terminating scheduled on node %v", pod.Name, pod.Spec.NodeName)
@@ -1107,8 +1107,9 @@ func (o *Options) evictPodWithoutPVInternal(ctx context.Context, attemptEvict bo
 	}
 }
 
-func (o *Options) waitForDelete(pods []*corev1.Pod, interval, timeout time.Duration, getPodFn func(string, string) (*corev1.Pod, error)) ([]*corev1.Pod, error) {
-	err := wait.PollImmediate(interval, timeout, func() (bool, error) {
+func (o *Options) waitForDelete(ctx context.Context, pods []*corev1.Pod, interval, timeout time.Duration, getPodFn func(string, string) (*corev1.Pod, error)) ([]*corev1.Pod, error) {
+	immediatePoll := true
+	err := wait.PollUntilContextTimeout(ctx, interval, timeout, immediatePoll, func(context.Context) (bool, error) {
 		pendingPods := []*corev1.Pod{}
 		for i, pod := range pods {
 			p, err := getPodFn(pod.Namespace, pod.Name)
diff --git a/pkg/util/provider/drain/volume_attachment.go b/pkg/util/provider/drain/volume_attachment.go
index 1c2426316..7cd544a17 100644
--- a/pkg/util/provider/drain/volume_attachment.go
+++ b/pkg/util/provider/drain/volume_attachment.go
@@ -27,7 +27,7 @@ func NewVolumeAttachmentHandler() *VolumeAttachmentHandler {
 	}
 }
 
-func (v *VolumeAttachmentHandler) dispatch(obj interface{}) {
+func (v *VolumeAttachmentHandler) dispatch(obj any) {
 	if len(v.workers) == 0 {
 		// As no workers are registered, nothing to do here.
 		return
@@ -57,13 +57,13 @@ func (v *VolumeAttachmentHandler) dispatch(obj interface{}) {
 }
 
 // AddVolumeAttachment is the event handler for VolumeAttachment add
-func (v *VolumeAttachmentHandler) AddVolumeAttachment(obj interface{}) {
+func (v *VolumeAttachmentHandler) AddVolumeAttachment(obj any) {
 	klog.V(4).Infof("Adding volume attachment object")
 	v.dispatch(obj)
 }
 
 // UpdateVolumeAttachment is the event handler for VolumeAttachment update
-func (v *VolumeAttachmentHandler) UpdateVolumeAttachment(_, newObj interface{}) {
+func (v *VolumeAttachmentHandler) UpdateVolumeAttachment(_, newObj any) {
 	klog.V(4).Info("Updating volume attachment object")
 	v.dispatch(newObj)
 }
diff --git a/pkg/util/provider/driver/driver.go b/pkg/util/provider/driver/driver.go
index b1c976d2e..dcd07d44f 100644
--- a/pkg/util/provider/driver/driver.go
+++ b/pkg/util/provider/driver/driver.go
@@ -170,7 +170,7 @@ type GetVolumeIDsResponse struct {
 type GenerateMachineClassForMigrationRequest struct {
 	// ProviderSpecificMachineClass is provider specfic machine class object.
 	// E.g. AWSMachineClass
-	ProviderSpecificMachineClass interface{}
+	ProviderSpecificMachineClass any
 	// MachineClass is the machine class object generated that is to be filled up
 	MachineClass *v1alpha1.MachineClass
 	// ClassSpec contains the class spec object to determine the machineClass kind
diff --git a/pkg/util/provider/machinecontroller/controller.go b/pkg/util/provider/machinecontroller/controller.go
index 2727ecb4c..4a9a584a9 100644
--- a/pkg/util/provider/machinecontroller/controller.go
+++ b/pkg/util/provider/machinecontroller/controller.go
@@ -78,18 +78,39 @@ func NewController(
 	)
 
 	controller := &controller{
-		namespace:                     namespace,
-		controlMachineClient:          controlMachineClient,
-		controlCoreClient:             controlCoreClient,
-		targetCoreClient:              targetCoreClient,
-		recorder:                      recorder,
-		secretQueue:                   workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "secret"),
-		nodeQueue:                     workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "node"),
-		machineClassQueue:             workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "machineclass"),
-		machineQueue:                  workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "machine"),
-		machineTerminationQueue:       workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "machinetermination"),
-		machineSafetyOrphanVMsQueue:   workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "machinesafetyorphanvms"),
-		machineSafetyAPIServerQueue:   workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "machinesafetyapiserver"),
+		namespace:            namespace,
+		controlMachineClient: controlMachineClient,
+		controlCoreClient:    controlCoreClient,
+		targetCoreClient:     targetCoreClient,
+		recorder:             recorder,
+		secretQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
+			workqueue.DefaultTypedControllerRateLimiter[string](),
+			workqueue.TypedRateLimitingQueueConfig[string]{Name: "secret"},
+		),
+		nodeQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
+			workqueue.DefaultTypedControllerRateLimiter[string](),
+			workqueue.TypedRateLimitingQueueConfig[string]{Name: "node"},
+		),
+		machineClassQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
+			workqueue.DefaultTypedControllerRateLimiter[string](),
+			workqueue.TypedRateLimitingQueueConfig[string]{Name: "machineclass"},
+		),
+		machineQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
+			workqueue.DefaultTypedControllerRateLimiter[string](),
+			workqueue.TypedRateLimitingQueueConfig[string]{Name: "machine"},
+		),
+		machineTerminationQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
+			workqueue.DefaultTypedControllerRateLimiter[string](),
+			workqueue.TypedRateLimitingQueueConfig[string]{Name: "machinetermination"},
+		),
+		machineSafetyOrphanVMsQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
+			workqueue.DefaultTypedControllerRateLimiter[string](),
+			workqueue.TypedRateLimitingQueueConfig[string]{Name: "machinesafetyorphanvms"},
+		),
+		machineSafetyAPIServerQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
+			workqueue.DefaultTypedControllerRateLimiter[string](),
+			workqueue.TypedRateLimitingQueueConfig[string]{Name: "machinesafetyapiserver"},
+		),
 		safetyOptions:                 safetyOptions,
 		nodeConditions:                nodeConditions,
 		driver:                        driver,
@@ -240,6 +261,10 @@ type controller struct {
 	// - lastAcquire time
 	// it is used to limit removal of `health timed out` machines
 	permitGiver permits.PermitGiver
+	// pendingMachineCreationMap keeps track of machines that are currently in
+	// creation flow, this is used to determine whether or not a machine should
+	// be processed by the termination queue.
+	pendingMachineCreationMap sync.Map
 
 	// control listers
 	secretLister       corelisters.SecretLister
@@ -253,13 +278,13 @@ type controller struct {
 	volumeAttachementLister storagelisters.VolumeAttachmentLister
 	podLister               corelisters.PodLister
 	// queues
-	secretQueue                 workqueue.RateLimitingInterface
-	nodeQueue                   workqueue.RateLimitingInterface
-	machineClassQueue           workqueue.RateLimitingInterface
-	machineQueue                workqueue.RateLimitingInterface
-	machineTerminationQueue     workqueue.RateLimitingInterface
-	machineSafetyOrphanVMsQueue workqueue.RateLimitingInterface
-	machineSafetyAPIServerQueue workqueue.RateLimitingInterface
+	secretQueue                 workqueue.TypedRateLimitingInterface[string]
+	nodeQueue                   workqueue.TypedRateLimitingInterface[string]
+	machineClassQueue           workqueue.TypedRateLimitingInterface[string]
+	machineQueue                workqueue.TypedRateLimitingInterface[string]
+	machineTerminationQueue     workqueue.TypedRateLimitingInterface[string]
+	machineSafetyOrphanVMsQueue workqueue.TypedRateLimitingInterface[string]
+	machineSafetyAPIServerQueue workqueue.TypedRateLimitingInterface[string]
 	// syncs
 	pvcSynced               cache.InformerSynced
 	pvSynced                cache.InformerSynced
diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go
index 4b60170c3..9b94722db 100644
--- a/pkg/util/provider/machinecontroller/machine.go
+++ b/pkg/util/provider/machinecontroller/machine.go
@@ -37,7 +37,7 @@ import (
 SECTION
 Machine controller - Machine add, update, delete watches
 */
-func (c *controller) addMachine(obj interface{}) {
+func (c *controller) addMachine(obj any) {
 	machine, ok := obj.(*v1alpha1.Machine)
 	if !ok {
 		klog.Errorf("couldn't convert to machine resource from object")
@@ -46,14 +46,14 @@ func (c *controller) addMachine(obj interface{}) {
 	// On restart of the controller process, a machine that was marked for
 	// deletion would be processed as part of an `add` event. This check
 	// ensures that its enqueued in the correct queue.
-	if machine.DeletionTimestamp != nil {
+	if c.shouldMachineBeMovedToTerminatingQueue(machine) {
 		c.enqueueMachineTermination(machine, "handling terminating machine object ADD event")
 	} else {
 		c.enqueueMachine(obj, "handling machine obj ADD event")
 	}
 }
 
-func (c *controller) updateMachine(oldObj, newObj interface{}) {
+func (c *controller) updateMachine(oldObj, newObj any) {
 	oldMachine := oldObj.(*v1alpha1.Machine)
 	newMachine := newObj.(*v1alpha1.Machine)
 
@@ -67,14 +67,14 @@ func (c *controller) updateMachine(oldObj, newObj interface{}) {
 		return
 	}
 
-	if newMachine.DeletionTimestamp != nil {
+	if c.shouldMachineBeMovedToTerminatingQueue(newMachine) {
 		c.enqueueMachineTermination(newMachine, "handling terminating machine object UPDATE event")
 	} else {
 		c.enqueueMachine(newObj, "handling machine object UPDATE event")
 	}
 }
 
-func (c *controller) deleteMachine(obj interface{}) {
+func (c *controller) deleteMachine(obj any) {
 	machine, ok := obj.(*v1alpha1.Machine)
 	if !ok {
 		tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
@@ -83,7 +83,7 @@ func (c *controller) deleteMachine(obj interface{}) {
 		}
 		machine, ok = tombstone.Obj.(*v1alpha1.Machine)
 		if !ok {
-			utilruntime.HandleError(fmt.Errorf("Tombstone contained object that is not a Machine Deployment %#v", obj))
+			utilruntime.HandleError(fmt.Errorf("tombstone contained object that is not a Machine %#v", obj))
 			return
 		}
 	}
@@ -91,7 +91,7 @@ func (c *controller) deleteMachine(obj interface{}) {
 }
 
 // getKeyForObj returns key for object, else returns false
-func (c *controller) getKeyForObj(obj interface{}) (string, bool) {
+func (c *controller) getKeyForObj(obj any) (string, bool) {
 	key, err := cache.MetaNamespaceKeyFunc(obj)
 	if err != nil {
 		klog.Errorf("Couldn't get key for object %+v: %v", obj, err)
@@ -100,14 +100,14 @@ func (c *controller) getKeyForObj(obj interface{}) (string, bool) {
 	return key, true
 }
 
-func (c *controller) enqueueMachine(obj interface{}, reason string) {
+func (c *controller) enqueueMachine(obj any, reason string) {
 	if key, ok := c.getKeyForObj(obj); ok {
 		klog.V(3).Infof("Adding machine object to queue %q, reason: %s", key, reason)
 		c.machineQueue.Add(key)
 	}
 }
 
-func (c *controller) enqueueMachineAfter(obj interface{}, after time.Duration, reason string) {
+func (c *controller) enqueueMachineAfter(obj any, after time.Duration, reason string) {
 	if key, ok := c.getKeyForObj(obj); ok {
 		klog.V(3).Infof("Adding machine object to queue %q after %s, reason: %s", key, after, reason)
 		c.machineQueue.AddAfter(key, after)
@@ -153,8 +153,15 @@ func (c *controller) reconcileClusterMachineKey(key string) error {
 		return err
 	}
 
-	if machine.DeletionTimestamp != nil {
+	// Add finalizers if not present on machine object
+	_, err = c.addMachineFinalizers(ctx, machine)
+	if err != nil {
+		return err
+	}
+
+	if c.shouldMachineBeMovedToTerminatingQueue(machine) {
 		klog.Errorf("Machine %q should be in machine termination queue", machine.Name)
+		c.enqueueMachineTermination(machine, "handling terminating machine object")
 		return nil
 	}
 
@@ -202,12 +209,6 @@ func (c *controller) reconcileClusterMachine(ctx context.Context, machine *v1alp
 		return retry, err
 	}
 
-	// Add finalizers if not present on machine object
-	retry, err = c.addMachineFinalizers(ctx, machine)
-	if err != nil {
-		return retry, err
-	}
-
 	if machine.Labels[v1alpha1.NodeLabelKey] != "" && machine.Status.CurrentStatus.Phase != "" {
 		// If reference to node object exists execute the below
 		retry, err := c.reconcileMachineHealth(ctx, machine)
@@ -276,7 +277,7 @@ func (c *controller) reconcileClusterMachineTermination(key string) error {
 	if err != nil {
 		klog.Errorf("cannot reconcile machine %q: %s", machine.Name, err)
 		c.enqueueMachineTerminationAfter(machine, time.Duration(retry), err.Error())
-		return err
+		return nil
 	}
 
 	// Process a delete event
@@ -291,15 +292,14 @@ func (c *controller) reconcileClusterMachineTermination(key string) error {
 
 	if err != nil {
 		c.enqueueMachineTerminationAfter(machine, time.Duration(retryPeriod), err.Error())
-		return err
 	} else {
 		// If the informer loses connection to the API server it may need to resync.
 		// If a resource is deleted while the watch is down, the informer won’t get
 		// delete event because the object is already gone. To avoid this edge-case,
 		// a requeue is scheduled post machine deletion as well.
 		c.enqueueMachineTerminationAfter(machine, time.Duration(retryPeriod), "post-deletion reconcile")
-		return nil
 	}
+	return nil
 }
 
 /*
@@ -311,7 +311,7 @@ var (
 	errNoMachineMatch       = errors.New("no machines matching node found")
 )
 
-func (c *controller) addNodeToMachine(obj interface{}) {
+func (c *controller) addNodeToMachine(obj any) {
 	node := obj.(*corev1.Node)
 	if node == nil {
 		klog.Errorf("Couldn't convert to node from object")
@@ -349,7 +349,7 @@ func (c *controller) addNodeToMachine(obj interface{}) {
 	}
 }
 
-func (c *controller) updateNodeToMachine(oldObj, newObj interface{}) {
+func (c *controller) updateNodeToMachine(oldObj, newObj any) {
 	oldNode := oldObj.(*corev1.Node)
 	node := newObj.(*corev1.Node)
 	if node == nil {
@@ -390,7 +390,7 @@ func (c *controller) updateNodeToMachine(oldObj, newObj interface{}) {
 	c.addNodeToMachine(newObj)
 }
 
-func (c *controller) deleteNodeToMachine(obj interface{}) {
+func (c *controller) deleteNodeToMachine(obj any) {
 	key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
 	if err != nil {
 		klog.Errorf("Couldn't get key for object %+v: %v", obj, err)
@@ -494,6 +494,10 @@ func (c *controller) triggerCreationFlow(ctx context.Context, createMachineReque
 		uninitializedMachine = false
 		addresses            = sets.New[corev1.NodeAddress]()
 	)
+	c.markCreationProcessing(machine)
+	defer func() {
+		c.unmarkCreationProcessing(machine)
+	}()
 
 	// This field is only modified during the creation flow. We have to assume that every Address that was added to the
 	// status in the past remains valid, otherwise we have no way of keeping the addresses that might be only returned
@@ -534,8 +538,8 @@ func (c *controller) triggerCreationFlow(ctx context.Context, createMachineReque
 			// Either VM is not found
 			// or GetMachineStatus() call is not implemented
 			// In this case, invoke a CreateMachine() call
-			if _, present := machine.Labels[v1alpha1.NodeLabelKey]; !present {
-				// If node label is not present
+			if machine.Spec.ProviderID == "" {
+				// If no providerID is present
 				klog.V(2).Infof("Creating a VM for machine %q, please wait!", machine.Name)
 				klog.V(2).Infof("The machine creation is triggered with timeout of %s", c.getEffectiveCreationTimeout(createMachineRequest.Machine).Duration)
 				createMachineResponse, err := c.driver.CreateMachine(ctx, createMachineRequest)
@@ -607,8 +611,9 @@ func (c *controller) triggerCreationFlow(ctx context.Context, createMachineReque
 				}
 				uninitializedMachine = true
 			} else {
-				// if node label present that means there must be a backing VM ,without need of GetMachineStatus() call
+				// if .spec.ProviderID is present that means there must be a backing VM, without need of GetMachineStatus() call
 				nodeName = machine.Labels[v1alpha1.NodeLabelKey]
+				providerID = machine.Spec.ProviderID
 			}
 
 		case codes.Uninitialized:
@@ -785,6 +790,10 @@ func (c *controller) triggerDeletionFlow(ctx context.Context, deleteMachineReque
 	)
 
 	switch {
+	case c.isCreationProcessing(machine):
+		err := fmt.Errorf("machine %q is in creation flow. Deletion cannot proceed", machine.Name)
+		return machineutils.MediumRetry, err
+
 	case !finalizers.Has(MCMFinalizerName):
 		// If Finalizers are not present on machine
 		err := fmt.Errorf("Machine %q is missing finalizers. Deletion cannot proceed", machine.Name)
@@ -857,3 +866,31 @@ func buildAddressStatus(addresses sets.Set[corev1.NodeAddress], nodeName string)
 	})
 	return res
 }
+
+func getMachineKey(machine *v1alpha1.Machine) string {
+	machineNamespacedName, err := cache.MetaNamespaceKeyFunc(machine)
+	if err != nil {
+		machineNamespacedName = fmt.Sprintf("%s/%s", machine.Namespace, machine.Name)
+		klog.Errorf("couldn't get key for machine %q, using %q instead: %v", machine.Name, machineNamespacedName, err)
+	}
+	return machineNamespacedName
+}
+
+func (c *controller) shouldMachineBeMovedToTerminatingQueue(machine *v1alpha1.Machine) bool {
+	if machine.DeletionTimestamp != nil && c.isCreationProcessing(machine) {
+		klog.Warningf("Cannot delete machine %q, its deletionTimestamp is set but it is currently being processed by the creation flow\n", getMachineKey(machine))
+	}
+
+	return !c.isCreationProcessing(machine) && machine.DeletionTimestamp != nil
+}
+
+func (c *controller) markCreationProcessing(machine *v1alpha1.Machine) {
+	c.pendingMachineCreationMap.Store(getMachineKey(machine), "")
+}
+func (c *controller) unmarkCreationProcessing(machine *v1alpha1.Machine) {
+	c.pendingMachineCreationMap.Delete(getMachineKey(machine))
+}
+func (c *controller) isCreationProcessing(machine *v1alpha1.Machine) bool {
+	_, isMachineInCreationFlow := c.pendingMachineCreationMap.Load(getMachineKey(machine))
+	return isMachineInCreationFlow
+}
diff --git a/pkg/util/provider/machinecontroller/machine_safety.go b/pkg/util/provider/machinecontroller/machine_safety.go
index 525063f6b..13d4bff84 100644
--- a/pkg/util/provider/machinecontroller/machine_safety.go
+++ b/pkg/util/provider/machinecontroller/machine_safety.go
@@ -305,7 +305,7 @@ func (c *controller) checkMachineClass(ctx context.Context, machineClass *v1alph
 }
 
 // updateMachineToSafety enqueues into machineSafetyQueue when a machine is updated to particular status
-func (c *controller) updateMachineToSafety(oldObj, newObj interface{}) {
+func (c *controller) updateMachineToSafety(oldObj, newObj any) {
 	oldMachine := oldObj.(*v1alpha1.Machine)
 	newMachine := newObj.(*v1alpha1.Machine)
 
@@ -321,7 +321,7 @@ func (c *controller) updateMachineToSafety(oldObj, newObj interface{}) {
 }
 
 // deleteMachineToSafety enqueues into machineSafetyQueue when a new machine is deleted
-func (c *controller) deleteMachineToSafety(obj interface{}) {
+func (c *controller) deleteMachineToSafety(obj any) {
 	machine := obj.(*v1alpha1.Machine)
 	if machine == nil {
 		klog.Errorf("Couldn't convert to machine resource from object")
@@ -331,6 +331,6 @@ func (c *controller) deleteMachineToSafety(obj interface{}) {
 }
 
 // enqueueMachineSafetyOrphanVMsKey enqueues into machineSafetyOrphanVMsQueue
-func (c *controller) enqueueMachineSafetyOrphanVMsKey(_ interface{}) {
+func (c *controller) enqueueMachineSafetyOrphanVMsKey(_ any) {
 	c.machineSafetyOrphanVMsQueue.Add("")
 }
diff --git a/pkg/util/provider/machinecontroller/machine_safety_util.go b/pkg/util/provider/machinecontroller/machine_safety_util.go
index e1ecbd111..ec1fc2926 100644
--- a/pkg/util/provider/machinecontroller/machine_safety_util.go
+++ b/pkg/util/provider/machinecontroller/machine_safety_util.go
@@ -6,6 +6,7 @@ package controller
 
 import (
 	"context"
+	"maps"
 
 	v1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -20,9 +21,7 @@ func (c *controller) updateNodeWithAnnotations(ctx context.Context, node *v1.Nod
 	}
 
 	//append annotations
-	for k, v := range annotations {
-		node.Annotations[k] = v
-	}
+	maps.Copy(node.Annotations, annotations)
 
 	_, err := c.targetCoreClient.CoreV1().Nodes().Update(ctx, node, metav1.UpdateOptions{})
 
diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go
index 7f76293ac..79822e1b9 100644
--- a/pkg/util/provider/machinecontroller/machine_util.go
+++ b/pkg/util/provider/machinecontroller/machine_util.go
@@ -28,6 +28,7 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
+	"maps"
 	"math"
 	"runtime"
 	"strconv"
@@ -221,13 +222,11 @@ func nodeConditionsHaveChanged(oldConditions []v1.NodeCondition, newConditions [
 	return addedOrUpdatedConditions, removedConditions, len(addedOrUpdatedConditions) != 0 || len(removedConditions) != 0
 }
 
-func mergeDataMaps(in map[string][]byte, maps ...map[string][]byte) map[string][]byte {
+func mergeDataMaps(in map[string][]byte, dataMaps ...map[string][]byte) map[string][]byte {
 	out := make(map[string][]byte)
 
-	for _, m := range append([]map[string][]byte{in}, maps...) {
-		for k, v := range m {
-			out[k] = v
-		}
+	for _, m := range append([]map[string][]byte{in}, dataMaps...) {
+		maps.Copy(out, m)
 	}
 
 	return out
@@ -1576,9 +1575,11 @@ func (c *controller) drainNode(ctx context.Context, deleteMachineRequest *driver
 		ReadonlyFilesystem   v1.NodeConditionType = "ReadonlyFilesystem"
 	)
 
-	forceDeleteLabelPresent, err = strconv.ParseBool(machine.Labels["force-deletion"])
-	if err != nil {
-		klog.Warningf("%q label for machine %q has invalid value: %s", "force-deletion", machine.Name, err)
+	if labelValue, exists := machine.Labels["force-deletion"]; exists {
+		forceDeleteLabelPresent, err = strconv.ParseBool(labelValue)
+		if err != nil {
+			klog.Warningf("%q label for machine %q has invalid value %q: %s", "force-deletion", machine.Name, labelValue, err)
+		}
 	}
 
 	if nodeName == "" {
@@ -2120,8 +2121,8 @@ func (c *controller) canMarkMachineFailed(machineDeployName, machineName, namesp
 	return false, nil
 }
 
-func (c *controller) waitForFailedMachineCacheUpdate(machine *v1alpha1.Machine, syncedPollPeriod, timeout time.Duration) bool {
-	pollErr := wait.Poll(syncedPollPeriod, timeout, func() (bool, error) {
+func (c *controller) waitForFailedMachineCacheUpdate(ctx context.Context, machine *v1alpha1.Machine, syncedPollPeriod, timeout time.Duration) bool {
+	pollErr := wait.PollUntilContextTimeout(ctx, syncedPollPeriod, timeout, false, func(context.Context) (bool, error) {
 		cachedMachine, err := c.machineLister.Machines(machine.Namespace).Get(machine.Name)
 		if apierrors.IsNotFound(err) {
 			return true, nil
@@ -2167,7 +2168,7 @@ func (c *controller) tryMarkingMachineFailed(ctx context.Context, machine, clone
 				var updated bool
 				updated, err = c.updateMachineToFailedState(ctx, description, machine, clone)
 				// wait for cache sync
-				if updated && !c.waitForFailedMachineCacheUpdate(machine, pollInterval, cacheUpdateTimeout) {
+				if updated && !c.waitForFailedMachineCacheUpdate(ctx, machine, pollInterval, cacheUpdateTimeout) {
 					// waiting 10 sec since nothing else can be done if cache update is failing
 					klog.Infof("cache sync returned false, waiting 10 sec , machineName=%q", machine.Name)
 					// TODO: This needs to be enhanced as cache update is not guaranteed.
diff --git a/pkg/util/provider/machinecontroller/machineclass.go b/pkg/util/provider/machinecontroller/machineclass.go
index 975dfce20..fb2193397 100644
--- a/pkg/util/provider/machinecontroller/machineclass.go
+++ b/pkg/util/provider/machinecontroller/machineclass.go
@@ -22,7 +22,7 @@ import (
 	"github.com/gardener/machine-controller-manager/pkg/util/provider/machineutils"
 )
 
-func (c *controller) machineToMachineClassAdd(obj interface{}) {
+func (c *controller) machineToMachineClassAdd(obj any) {
 	machine, ok := obj.(*v1alpha1.Machine)
 	if machine == nil || !ok {
 		klog.Warningf("Couldn't get machine from object: %+v", obj)
@@ -33,11 +33,11 @@ func (c *controller) machineToMachineClassAdd(obj interface{}) {
 	}
 }
 
-func (c *controller) machineToMachineClassDelete(obj interface{}) {
+func (c *controller) machineToMachineClassDelete(obj any) {
 	c.machineToMachineClassAdd(obj)
 }
 
-func (c *controller) machineClassAdd(obj interface{}) {
+func (c *controller) machineClassAdd(obj any) {
 	key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
 	if err != nil {
 		klog.Errorf("Couldn't get key for object %+v: %v", obj, err)
@@ -46,7 +46,7 @@ func (c *controller) machineClassAdd(obj interface{}) {
 	c.machineClassQueue.Add(key)
 }
 
-func (c *controller) machineClassUpdate(oldObj, newObj interface{}) {
+func (c *controller) machineClassUpdate(oldObj, newObj any) {
 	old, ok := oldObj.(*v1alpha1.MachineClass)
 	if old == nil || !ok {
 		return
@@ -59,7 +59,7 @@ func (c *controller) machineClassUpdate(oldObj, newObj interface{}) {
 	c.machineClassAdd(newObj)
 }
 
-func (c *controller) machineClassDelete(obj interface{}) {
+func (c *controller) machineClassDelete(obj any) {
 	c.machineClassAdd(obj)
 }
 
@@ -88,7 +88,7 @@ func (c *controller) reconcileClusterMachineClassKey(key string) error {
 		c.enqueueMachineClassAfter(class, time.Duration(machineutils.ShortRetry))
 	} else {
 		// Re-enqueue periodically to avoid missing of events
-		// TODO: Get ride of this logic
+		// TODO: Get rid of this logic
 		c.enqueueMachineClassAfter(class, time.Duration(machineutils.LongRetry))
 	}
 
@@ -131,7 +131,11 @@ func (c *controller) reconcileClusterMachineClass(ctx context.Context, class *v1
 		}
 
 		for _, m := range machines {
-			c.enqueueMachine(m, reason)
+			// Enqueue only the non-terminating machines to support changes to virtual capacity to nodes.
+			// Changes to virtual capacity need not be reflected on terminating machines as they are being deleted.
+			if m.DeletionTimestamp == nil {
+				c.enqueueMachine(m, reason)
+			}
 		}
 		return nil
 	}
@@ -139,11 +143,6 @@ func (c *controller) reconcileClusterMachineClass(ctx context.Context, class *v1
 	if len(machines) > 0 {
 		// Machines are still referring the machine class, please wait before deletion
 		klog.V(3).Infof("Cannot remove finalizer on %s because still (%d) machines are referencing it", class.Name, len(machines))
-
-		for _, machine := range machines {
-			c.addMachine(machine)
-		}
-
 		return fmt.Errorf("Retry as machine objects are still referring the machineclass")
 	}
 
@@ -194,7 +193,7 @@ func (c *controller) updateMachineClassFinalizers(ctx context.Context, class *v1
 	return err
 }
 
-func (c *controller) enqueueMachineClassAfter(obj interface{}, after time.Duration) {
+func (c *controller) enqueueMachineClassAfter(obj any, after time.Duration) {
 	key, err := cache.MetaNamespaceKeyFunc(obj)
 	if err != nil {
 		return
diff --git a/pkg/util/provider/machinecontroller/metrics.go b/pkg/util/provider/machinecontroller/metrics.go
index 7d6a21a8f..61ce12f03 100644
--- a/pkg/util/provider/machinecontroller/metrics.go
+++ b/pkg/util/provider/machinecontroller/metrics.go
@@ -19,6 +19,7 @@ import (
 // Describe is method required to implement the prometheus.Collect interface.
 func (c *controller) Describe(ch chan<- *prometheus.Desc) {
 	ch <- metrics.MachineCountDesc
+	ch <- metrics.MachineCSPhase
 }
 
 // Collect is method required to implement the prometheus.Collect interface.
@@ -41,7 +42,7 @@ func (c *controller) CollectMachineMetrics(ch chan<- prometheus.Metric) {
 		mSpec := machine.Spec
 		updateMachineInfoMetric(mMeta, mSpec)
 		updateMachineStatusConditionMetric(machine, mMeta)
-		updateMachineCSPhaseMetric(machine, mMeta)
+		updateMachineCSPhaseMetric(machine, mMeta, ch)
 	}
 
 	updateMachineCountMetric(ch, machineList)
@@ -70,7 +71,7 @@ func updateMachineCountMetric(ch chan<- prometheus.Metric, machineList []*v1alph
 	ch <- metric
 }
 
-func updateMachineCSPhaseMetric(machine *v1alpha1.Machine, mMeta metav1.ObjectMeta) {
+func updateMachineCSPhaseMetric(machine *v1alpha1.Machine, mMeta metav1.ObjectMeta, ch chan<- prometheus.Metric) {
 	var phase float64
 	switch machine.Status.CurrentStatus.Phase {
 	case v1alpha1.MachineTerminating:
@@ -86,10 +87,14 @@ func updateMachineCSPhaseMetric(machine *v1alpha1.Machine, mMeta metav1.ObjectMe
 	case v1alpha1.MachineRunning:
 		phase = 1
 	}
-	metrics.MachineCSPhase.With(prometheus.Labels{
-		"name":      mMeta.Name,
-		"namespace": mMeta.Namespace,
-	}).Set(phase)
+
+	ch <- prometheus.MustNewConstMetric(
+		metrics.MachineCSPhase,
+		prometheus.GaugeValue,
+		phase,
+		mMeta.Name,
+		mMeta.Namespace,
+	)
 }
 
 func updateMachineStatusConditionMetric(machine *v1alpha1.Machine, mMeta metav1.ObjectMeta) {
diff --git a/pkg/util/provider/machinecontroller/node.go b/pkg/util/provider/machinecontroller/node.go
index 74af469eb..74d579903 100644
--- a/pkg/util/provider/machinecontroller/node.go
+++ b/pkg/util/provider/machinecontroller/node.go
@@ -14,7 +14,7 @@ import (
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 )
 
-func (c *controller) nodeAdd(obj interface{}) {
+func (c *controller) nodeAdd(obj any) {
 	key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
 	if err != nil {
 		klog.Errorf("Couldn't get key for object %+v: %v", obj, err)
@@ -23,11 +23,11 @@ func (c *controller) nodeAdd(obj interface{}) {
 	c.nodeQueue.Add(key)
 }
 
-func (c *controller) nodeUpdate(newObj interface{}) {
+func (c *controller) nodeUpdate(newObj any) {
 	c.nodeAdd(newObj)
 }
 
-func (c *controller) nodeDelete(obj interface{}) {
+func (c *controller) nodeDelete(obj any) {
 	node, _ := obj.(*v1.Node)
 	if node == nil {
 		return
diff --git a/pkg/util/provider/machinecontroller/secret.go b/pkg/util/provider/machinecontroller/secret.go
index 4e63f9b03..d3ea00786 100644
--- a/pkg/util/provider/machinecontroller/secret.go
+++ b/pkg/util/provider/machinecontroller/secret.go
@@ -126,7 +126,7 @@ func (c *controller) updateSecretFinalizers(ctx context.Context, secret *corev1.
 	Event handlers
 */
 
-func (c *controller) secretAdd(obj interface{}) {
+func (c *controller) secretAdd(obj any) {
 	key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
 	if err != nil {
 		klog.Errorf("Couldn't get key for object %+v: %v", obj, err)
@@ -135,11 +135,11 @@ func (c *controller) secretAdd(obj interface{}) {
 	c.secretQueue.Add(key)
 }
 
-func (c *controller) secretDelete(obj interface{}) {
+func (c *controller) secretDelete(obj any) {
 	c.secretAdd(obj)
 }
 
-func (c *controller) enqueueSecretAfter(obj interface{}, after time.Duration) {
+func (c *controller) enqueueSecretAfter(obj any, after time.Duration) {
 	key, err := cache.MetaNamespaceKeyFunc(obj)
 	if err != nil {
 		return
@@ -147,7 +147,7 @@ func (c *controller) enqueueSecretAfter(obj interface{}, after time.Duration) {
 	c.secretQueue.AddAfter(key, after)
 }
 
-func enqueueSecretForReferences(queue workqueue.RateLimitingInterface, secretRefs ...*corev1.SecretReference) {
+func enqueueSecretForReferences(queue workqueue.TypedRateLimitingInterface[string], secretRefs ...*corev1.SecretReference) {
 	for _, secretRef := range secretRefs {
 		if secretRef != nil {
 			queue.Add(secretRef.Namespace + "/" + secretRef.Name)
@@ -155,7 +155,7 @@ func enqueueSecretForReferences(queue workqueue.RateLimitingInterface, secretRef
 	}
 }
 
-func enqueueSecretForReferenceIfChanged(queue workqueue.RateLimitingInterface, oldSecretRef, newSecretRef *corev1.SecretReference) {
+func enqueueSecretForReferenceIfChanged(queue workqueue.TypedRateLimitingInterface[string], oldSecretRef, newSecretRef *corev1.SecretReference) {
 	if !apiequality.Semantic.DeepEqual(oldSecretRef, newSecretRef) {
 		if oldSecretRef != nil {
 			queue.Add(oldSecretRef.Namespace + "/" + oldSecretRef.Name)
@@ -166,7 +166,7 @@ func enqueueSecretForReferenceIfChanged(queue workqueue.RateLimitingInterface, o
 	}
 }
 
-func (c *controller) machineClassToSecretAdd(obj interface{}) {
+func (c *controller) machineClassToSecretAdd(obj any) {
 	machineClass, ok := obj.(*v1alpha1.MachineClass)
 	if !ok || machineClass == nil || machineClass.SecretRef == nil {
 		return
@@ -175,7 +175,7 @@ func (c *controller) machineClassToSecretAdd(obj interface{}) {
 	enqueueSecretForReferences(c.secretQueue, machineClass.SecretRef, machineClass.CredentialsSecretRef)
 }
 
-func (c *controller) machineClassToSecretUpdate(oldObj interface{}, newObj interface{}) {
+func (c *controller) machineClassToSecretUpdate(oldObj any, newObj any) {
 	oldMachineClass, ok := oldObj.(*v1alpha1.MachineClass)
 	if !ok || oldMachineClass == nil || oldMachineClass.SecretRef == nil {
 		return
@@ -189,6 +189,6 @@ func (c *controller) machineClassToSecretUpdate(oldObj interface{}, newObj inter
 	enqueueSecretForReferenceIfChanged(c.secretQueue, oldMachineClass.CredentialsSecretRef, newMachineClass.CredentialsSecretRef)
 }
 
-func (c *controller) machineClassToSecretDelete(obj interface{}) {
+func (c *controller) machineClassToSecretDelete(obj any) {
 	c.machineClassToSecretAdd(obj)
 }
diff --git a/pkg/util/provider/machinecontroller/userdata.go b/pkg/util/provider/machinecontroller/userdata.go
index 7cf790b89..9dd55c5c8 100644
--- a/pkg/util/provider/machinecontroller/userdata.go
+++ b/pkg/util/provider/machinecontroller/userdata.go
@@ -118,7 +118,7 @@ func (c *controller) getBootstrapTokenOrCreateIfNotExist(ctx context.Context, ma
 				return nil, err
 			}
 			data := map[string][]byte{
-				bootstraptokenapi.BootstrapTokenDescriptionKey:      []byte(fmt.Sprintf("A bootstrap token for machine %q generated by MachineControllerManager.", machine.Name)),
+				bootstraptokenapi.BootstrapTokenDescriptionKey:      fmt.Appendf(nil, "A bootstrap token for machine %q generated by MachineControllerManager.", machine.Name),
 				bootstraptokenapi.BootstrapTokenIDKey:               []byte(tokenID),
 				bootstraptokenapi.BootstrapTokenSecretKey:           []byte(bootstrapTokenSecretKey),
 				bootstraptokenapi.BootstrapTokenExpirationKey:       []byte(metav1.Now().Add(c.getEffectiveCreationTimeout(machine).Duration).Format(time.RFC3339)),
diff --git a/pkg/util/provider/metrics/metrics.go b/pkg/util/provider/metrics/metrics.go
index 68efded3e..b44aed9a0 100644
--- a/pkg/util/provider/metrics/metrics.go
+++ b/pkg/util/provider/metrics/metrics.go
@@ -24,12 +24,11 @@ var (
 	MachineCountDesc = prometheus.NewDesc("mcm_machine_items_total", "Count of machines currently managed by the mcm.", nil, nil)
 
 	// MachineCSPhase Current status phase of the Machines currently managed by the mcm.
-	MachineCSPhase = prometheus.NewGaugeVec(prometheus.GaugeOpts{
-		Namespace: namespace,
-		Subsystem: machineSubsystem,
-		Name:      "current_status_phase",
-		Help:      "Current status phase of the Machines currently managed by the mcm.",
-	}, []string{"name", "namespace"})
+	MachineCSPhase = prometheus.NewDesc(
+		prometheus.BuildFQName(namespace, machineSubsystem, "current_status_phase"),
+		"Current status phase of the Machines currently managed by the mcm.",
+		[]string{"name", "namespace"},
+		nil)
 
 	// MachineInfo Information of the Machines currently managed by the mcm.
 	MachineInfo = prometheus.NewGaugeVec(prometheus.GaugeOpts{
@@ -112,7 +111,6 @@ var (
 func registerMachineSubsystemMetrics() {
 	prometheus.MustRegister(MachineInfo)
 	prometheus.MustRegister(MachineStatusCondition)
-	prometheus.MustRegister(MachineCSPhase)
 }
 
 func registerCloudAPISubsystemMetrics() {
diff --git a/pkg/util/worker/worker.go b/pkg/util/worker/worker.go
index f7173db23..87b52ff95 100644
--- a/pkg/util/worker/worker.go
+++ b/pkg/util/worker/worker.go
@@ -21,7 +21,7 @@ const (
 // Run creates and runs a worker routine that just processes items in the
 // specified queue. The worker will run until stopCh is closed. The worker will be
 // added to the wait group when started and marked done when finished.
-func Run(queue workqueue.RateLimitingInterface, resourceType string, maxRetries int, forgetAfterSuccess bool, reconciler func(key string) error, stopCh <-chan struct{}, waitGroup *sync.WaitGroup) {
+func Run(queue workqueue.TypedRateLimitingInterface[string], resourceType string, maxRetries int, forgetAfterSuccess bool, reconciler func(key string) error, stopCh <-chan struct{}, waitGroup *sync.WaitGroup) {
 	waitGroup.Add(1)
 	go func() {
 		wait.Until(worker(queue, resourceType, maxRetries, forgetAfterSuccess, reconciler), time.Second, stopCh)
@@ -34,7 +34,7 @@ func Run(queue workqueue.RateLimitingInterface, resourceType string, maxRetries
 // It enforces that the reconciler is never invoked concurrently with the same key.
 // If forgetAfterSuccess is true, it will cause the queue to forget the item should reconciliation
 // have no error.
-func worker(queue workqueue.RateLimitingInterface, resourceType string, maxRetries int, forgetAfterSuccess bool, reconciler func(key string) error) func() {
+func worker(queue workqueue.TypedRateLimitingInterface[string], resourceType string, maxRetries int, forgetAfterSuccess bool, reconciler func(key string) error) func() {
 	return func() {
 		exit := false
 		for !exit {
@@ -45,7 +45,7 @@ func worker(queue workqueue.RateLimitingInterface, resourceType string, maxRetri
 				}
 				defer queue.Done(key)
 
-				err := reconciler(key.(string))
+				err := reconciler(key)
 				if err == nil {
 					if forgetAfterSuccess {
 						queue.Forget(key)



Test patch:
diff --git a/pkg/controller/controller_suite_test.go b/pkg/controller/controller_suite_test.go
index 6ad214e7f..55b1fe7d3 100644
--- a/pkg/controller/controller_suite_test.go
+++ b/pkg/controller/controller_suite_test.go
@@ -9,6 +9,7 @@ import (
 	"flag"
 	"fmt"
 	"io"
+	"maps"
 	"testing"
 	"time"
 
@@ -24,7 +25,7 @@ import (
 	"k8s.io/client-go/tools/record"
 	"k8s.io/client-go/util/workqueue"
 	"k8s.io/klog/v2"
-	"k8s.io/utils/pointer"
+	"k8s.io/utils/ptr"
 
 	machine_internal "github.com/gardener/machine-controller-manager/pkg/apis/machine"
 	"github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1"
@@ -217,12 +218,8 @@ func newMachinesFromMachineSet(
 	t := &machineSet.TypeMeta
 
 	finalLabels := make(map[string]string, 0)
-	for k, v := range labels {
-		finalLabels[k] = v
-	}
-	for k, v := range machineSet.Spec.Template.Labels {
-		finalLabels[k] = v
-	}
+	maps.Copy(finalLabels, labels)
+	maps.Copy(finalLabels, machineSet.Spec.Template.Labels)
 
 	return newMachines(
 		machineCount,
@@ -233,8 +230,8 @@ func newMachinesFromMachineSet(
 			Kind:               t.Kind,
 			Name:               machineSet.Name,
 			UID:                machineSet.UID,
-			BlockOwnerDeletion: pointer.BoolPtr(true),
-			Controller:         pointer.BoolPtr(true),
+			BlockOwnerDeletion: ptr.To(true),
+			Controller:         ptr.To(true),
 		},
 		annotations,
 		finalLabels,
@@ -434,27 +431,42 @@ func createController(
 	}
 
 	controller := &controller{
-		namespace:                      namespace,
-		safetyOptions:                  safetyOptions,
-		targetCoreClient:               fakeTargetCoreClient,
-		controlCoreClient:              fakeControlCoreClient,
-		controlMachineClient:           fakeTypedMachineClient,
-		internalExternalScheme:         internalExternalScheme,
-		nodeLister:                     nodes.Lister(),
-		machineLister:                  machines.Lister(),
-		machineSetLister:               machineSets.Lister(),
-		machineDeploymentLister:        machineDeployments.Lister(),
-		machineSynced:                  machines.Informer().HasSynced,
-		machineSetSynced:               machineSets.Informer().HasSynced,
-		machineDeploymentSynced:        machineDeployments.Informer().HasSynced,
-		nodeSynced:                     nodes.Informer().HasSynced,
-		nodeQueue:                      workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "node"),
-		machineQueue:                   workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "machine"),
-		machineSetQueue:                workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "machineset"),
-		machineDeploymentQueue:         workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "machinedeployment"),
-		machineSafetyOvershootingQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "machinesafetyovershooting"),
-		expectations:                   NewUIDTrackingContExpectations(NewContExpectations()),
-		recorder:                       record.NewBroadcaster().NewRecorder(internalExternalScheme, corev1.EventSource{Component: ""}),
+		namespace:               namespace,
+		safetyOptions:           safetyOptions,
+		targetCoreClient:        fakeTargetCoreClient,
+		controlCoreClient:       fakeControlCoreClient,
+		controlMachineClient:    fakeTypedMachineClient,
+		internalExternalScheme:  internalExternalScheme,
+		nodeLister:              nodes.Lister(),
+		machineLister:           machines.Lister(),
+		machineSetLister:        machineSets.Lister(),
+		machineDeploymentLister: machineDeployments.Lister(),
+		machineSynced:           machines.Informer().HasSynced,
+		machineSetSynced:        machineSets.Informer().HasSynced,
+		machineDeploymentSynced: machineDeployments.Informer().HasSynced,
+		nodeSynced:              nodes.Informer().HasSynced,
+		nodeQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
+			workqueue.DefaultTypedControllerRateLimiter[string](),
+			workqueue.TypedRateLimitingQueueConfig[string]{Name: "node"},
+		),
+		machineQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
+			workqueue.DefaultTypedControllerRateLimiter[string](),
+			workqueue.TypedRateLimitingQueueConfig[string]{Name: "machine"},
+		),
+		machineSetQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
+			workqueue.DefaultTypedControllerRateLimiter[string](),
+			workqueue.TypedRateLimitingQueueConfig[string]{Name: "machineset"},
+		),
+		machineDeploymentQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
+			workqueue.DefaultTypedControllerRateLimiter[string](),
+			workqueue.TypedRateLimitingQueueConfig[string]{Name: "machinedeployment"},
+		),
+		machineSafetyOvershootingQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
+			workqueue.DefaultTypedControllerRateLimiter[string](),
+			workqueue.TypedRateLimitingQueueConfig[string]{Name: "machinesafetyovershooting"},
+		),
+		expectations: NewUIDTrackingContExpectations(NewContExpectations()),
+		recorder:     record.NewBroadcaster().NewRecorder(internalExternalScheme, corev1.EventSource{Component: ""}),
 	}
 
 	// controller.internalExternalScheme = runtime.NewScheme()
diff --git a/pkg/controller/deployment_rollback_test.go b/pkg/controller/deployment_rollback_test.go
deleted file mode 100644
index 7a63caa7c..000000000
--- a/pkg/controller/deployment_rollback_test.go
+++ /dev/null
@@ -1,193 +0,0 @@
-// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
-//
-// SPDX-License-Identifier: Apache-2.0
-
-package controller
-
-import (
-	"context"
-
-	. "github.com/onsi/ginkgo/v2"
-	. "github.com/onsi/gomega"
-	corev1 "k8s.io/api/core/v1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/runtime"
-
-	machinev1 "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1"
-)
-
-var _ = Describe("deployment_rollback", func() {
-
-	Describe("#removeTaintNodesBackingMachineSet", func() {
-		type setup struct {
-			nodes       []*corev1.Node
-			machineSets []*machinev1.MachineSet
-			machines    []*machinev1.Machine
-		}
-		type expect struct {
-			nodes       []*corev1.Node
-			machineSets []*machinev1.MachineSet
-			err         bool
-		}
-		type data struct {
-			setup  setup
-			action *machinev1.MachineSet
-			expect expect
-		}
-		objMeta := &metav1.ObjectMeta{
-			Namespace: testNamespace,
-		}
-		machineSets := newMachineSets(
-			1,
-			&machinev1.MachineTemplateSpec{
-				ObjectMeta: metav1.ObjectMeta{
-					Name: "machineset-0",
-					Labels: map[string]string{
-						"key": "value",
-					},
-				},
-				Spec: machinev1.MachineSpec{
-					Class: machinev1.ClassSpec{
-						Kind: "OpenStackMachineClass",
-						Name: "test-machine-class",
-					},
-				},
-			},
-			3,
-			500,
-			nil,
-			nil,
-			map[string]string{
-				PreferNoScheduleKey: "True",
-			},
-			nil,
-		)
-
-		DescribeTable("##table",
-			func(data *data) {
-				stop := make(chan struct{})
-				defer close(stop)
-
-				controlMachineObjects := []runtime.Object{}
-				for _, o := range data.setup.machineSets {
-					controlMachineObjects = append(controlMachineObjects, o)
-				}
-				for _, o := range data.setup.machines {
-					controlMachineObjects = append(controlMachineObjects, o)
-				}
-
-				targetCoreObjects := []runtime.Object{}
-				for _, o := range data.setup.nodes {
-					targetCoreObjects = append(targetCoreObjects, o)
-				}
-
-				controller, trackers := createController(stop, testNamespace, controlMachineObjects, nil, targetCoreObjects)
-				defer trackers.Stop()
-				waitForCacheSync(stop, controller)
-
-				err := controller.removeTaintNodesBackingMachineSet(
-					context.TODO(),
-					data.action,
-					&corev1.Taint{
-						Key:    PreferNoScheduleKey,
-						Value:  "True",
-						Effect: "PreferNoSchedule",
-					})
-
-				if !data.expect.err {
-					Expect(err).To(BeNil())
-				} else {
-					Expect(err).To(HaveOccurred())
-				}
-
-				for _, expectedMachineSet := range data.expect.machineSets {
-					actualMachineSet, err := controller.controlMachineClient.MachineSets(testNamespace).Get(context.TODO(), expectedMachineSet.Name, metav1.GetOptions{})
-					Expect(err).ToNot(HaveOccurred())
-					Expect(actualMachineSet.Annotations).Should(Equal(expectedMachineSet.Annotations))
-				}
-
-				for _, expectedNode := range data.expect.nodes {
-					actualNode, err := controller.targetCoreClient.CoreV1().Nodes().Get(context.TODO(), expectedNode.Name, metav1.GetOptions{})
-					Expect(err).ToNot(HaveOccurred())
-					Expect(actualNode.Spec.Taints).Should(ConsistOf(expectedNode.Spec.Taints))
-				}
-
-			},
-			Entry("removed taints on nodes backing machineSet", &data{
-				setup: setup{
-					machineSets: machineSets,
-					machines: newMachinesFromMachineSet(
-						1,
-						machineSets[0],
-						&machinev1.MachineStatus{},
-						nil,
-						map[string]string{machinev1.NodeLabelKey: "node-0"},
-					),
-					nodes: newNodes(
-						1,
-						nil,
-						&corev1.NodeSpec{
-							Taints: []corev1.Taint{
-								{
-									Key:    PreferNoScheduleKey,
-									Value:  "True",
-									Effect: "PreferNoSchedule",
-								},
-							},
-						},
-						nil,
-					),
-				},
-				action: newMachineSets(
-					1,
-					&machinev1.MachineTemplateSpec{
-						ObjectMeta: *newObjectMeta(objMeta, 0),
-						Spec: machinev1.MachineSpec{
-							Class: machinev1.ClassSpec{
-								Kind: "OpenStackMachineClass",
-								Name: "test-machine-class",
-							},
-						},
-					},
-					3,
-					500,
-					nil,
-					nil,
-					map[string]string{
-						PreferNoScheduleKey: "True",
-					},
-					nil,
-				)[0],
-				expect: expect{
-					machineSets: newMachineSets(
-						1,
-						&machinev1.MachineTemplateSpec{
-							ObjectMeta: *newObjectMeta(objMeta, 0),
-							Spec: machinev1.MachineSpec{
-								Class: machinev1.ClassSpec{
-									Kind: "OpenStackMachineClass",
-									Name: "test-machine-class",
-								},
-							},
-						},
-						3,
-						500,
-						nil,
-						nil,
-						map[string]string{},
-						nil,
-					),
-					nodes: newNodes(
-						1,
-						nil,
-						&corev1.NodeSpec{
-							Taints: []corev1.Taint{},
-						},
-						nil,
-					),
-					err: false,
-				},
-			}),
-		)
-	})
-})
diff --git a/pkg/controller/deployment_test.go b/pkg/controller/deployment_test.go
index e1d6565f9..f9c738b8e 100644
--- a/pkg/controller/deployment_test.go
+++ b/pkg/controller/deployment_test.go
@@ -886,7 +886,7 @@ var _ = Describe("machineDeployment", func() {
 
 				defer trackers.Stop()
 				waitForCacheSync(stop, c)
-				c.deleteMachineToMachineDeployment(context.Background(), testMachine)
+				c.deleteMachineToMachineDeployment(testMachine)
 
 				waitForCacheSync(stop, c)
 				Expect(c.machineDeploymentQueue.Len()).To(Equal(queueLength))
@@ -1359,7 +1359,7 @@ var _ = Describe("machineDeployment", func() {
 
 				defer trackers.Stop()
 				waitForCacheSync(stop, c)
-				actualMachineSets, err := c.getMachineSetsForMachineDeployment(context.Background(), testMachineDeployment)
+				actualMachineSets, err := c.getMachineSetsForMachineDeployment(context.TODO(), testMachineDeployment)
 
 				waitForCacheSync(stop, c)
 				if expectedErr != nil {
@@ -2088,7 +2088,7 @@ var _ = Describe("machineDeployment", func() {
 
 				defer trackers.Stop()
 				waitForCacheSync(stop, c)
-				c.terminateMachineSets(context.Background(), testMachineSets, testMachineDeployment)
+				c.terminateMachineSets(context.TODO(), testMachineSets, testMachineDeployment)
 
 				waitForCacheSync(stop, c)
 				actualMachineSets, _ := c.controlMachineClient.MachineSets(testNamespace).List(context.Background(), metav1.ListOptions{})
@@ -2158,7 +2158,7 @@ var _ = Describe("machineDeployment", func() {
 
 				defer trackers.Stop()
 				waitForCacheSync(stop, c)
-				c.deleteMachineDeploymentFinalizers(context.Background(), testMachineDeployment)
+				c.deleteMachineDeploymentFinalizers(context.TODO(), testMachineDeployment)
 
 				waitForCacheSync(stop, c)
 				actualMachineDeployment, _ := c.controlMachineClient.MachineDeployments(testNamespace).Get(context.Background(), testMachineDeployment.Name, metav1.GetOptions{})
diff --git a/pkg/controller/deployment_util_test.go b/pkg/controller/deployment_util_test.go
index df6ec988d..58c62b3b5 100644
--- a/pkg/controller/deployment_util_test.go
+++ b/pkg/controller/deployment_util_test.go
@@ -5,12 +5,14 @@
 package controller
 
 import (
+	"context"
 	machinev1 "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1"
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
 	corev1 "k8s.io/api/core/v1"
 	apiequality "k8s.io/apimachinery/pkg/api/equality"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/utils/ptr"
 )
@@ -595,4 +597,177 @@ var _ = Describe("deployment_util", func() {
 			Expect(result).To(Equal(expected))
 		})
 	})
+
+	Describe("#removeTaintNodesBackingMachineSet", func() {
+		type setup struct {
+			nodes       []*corev1.Node
+			machineSets []*machinev1.MachineSet
+			machines    []*machinev1.Machine
+		}
+		type expect struct {
+			nodes       []*corev1.Node
+			machineSets []*machinev1.MachineSet
+			err         bool
+		}
+		type data struct {
+			setup  setup
+			action *machinev1.MachineSet
+			expect expect
+		}
+		objMeta := &metav1.ObjectMeta{
+			Namespace: testNamespace,
+		}
+		machineSets := newMachineSets(
+			1,
+			&machinev1.MachineTemplateSpec{
+				ObjectMeta: metav1.ObjectMeta{
+					Name: "machineset-0",
+					Labels: map[string]string{
+						"key": "value",
+					},
+				},
+				Spec: machinev1.MachineSpec{
+					Class: machinev1.ClassSpec{
+						Kind: "OpenStackMachineClass",
+						Name: "test-machine-class",
+					},
+				},
+			},
+			3,
+			500,
+			nil,
+			nil,
+			map[string]string{
+				PreferNoScheduleKey: "True",
+			},
+			nil,
+		)
+
+		DescribeTable("##table",
+			func(data *data) {
+				stop := make(chan struct{})
+				defer close(stop)
+
+				controlMachineObjects := []runtime.Object{}
+				for _, o := range data.setup.machineSets {
+					controlMachineObjects = append(controlMachineObjects, o)
+				}
+				for _, o := range data.setup.machines {
+					controlMachineObjects = append(controlMachineObjects, o)
+				}
+
+				targetCoreObjects := []runtime.Object{}
+				for _, o := range data.setup.nodes {
+					targetCoreObjects = append(targetCoreObjects, o)
+				}
+
+				controller, trackers := createController(stop, testNamespace, controlMachineObjects, nil, targetCoreObjects)
+				defer trackers.Stop()
+				waitForCacheSync(stop, controller)
+
+				err := controller.removeTaintNodesBackingMachineSet(
+					context.TODO(),
+					data.action,
+					&corev1.Taint{
+						Key:    PreferNoScheduleKey,
+						Value:  "True",
+						Effect: "PreferNoSchedule",
+					})
+
+				if !data.expect.err {
+					Expect(err).To(BeNil())
+				} else {
+					Expect(err).To(HaveOccurred())
+				}
+
+				for _, expectedMachineSet := range data.expect.machineSets {
+					actualMachineSet, err := controller.controlMachineClient.MachineSets(testNamespace).Get(context.TODO(), expectedMachineSet.Name, metav1.GetOptions{})
+					Expect(err).ToNot(HaveOccurred())
+					Expect(actualMachineSet.Annotations).Should(Equal(expectedMachineSet.Annotations))
+				}
+
+				for _, expectedNode := range data.expect.nodes {
+					actualNode, err := controller.targetCoreClient.CoreV1().Nodes().Get(context.TODO(), expectedNode.Name, metav1.GetOptions{})
+					Expect(err).ToNot(HaveOccurred())
+					Expect(actualNode.Spec.Taints).Should(ConsistOf(expectedNode.Spec.Taints))
+				}
+
+			},
+			Entry("removed taints on nodes backing machineSet", &data{
+				setup: setup{
+					machineSets: machineSets,
+					machines: newMachinesFromMachineSet(
+						1,
+						machineSets[0],
+						&machinev1.MachineStatus{},
+						nil,
+						map[string]string{machinev1.NodeLabelKey: "node-0"},
+					),
+					nodes: newNodes(
+						1,
+						nil,
+						&corev1.NodeSpec{
+							Taints: []corev1.Taint{
+								{
+									Key:    PreferNoScheduleKey,
+									Value:  "True",
+									Effect: "PreferNoSchedule",
+								},
+							},
+						},
+						nil,
+					),
+				},
+				action: newMachineSets(
+					1,
+					&machinev1.MachineTemplateSpec{
+						ObjectMeta: *newObjectMeta(objMeta, 0),
+						Spec: machinev1.MachineSpec{
+							Class: machinev1.ClassSpec{
+								Kind: "OpenStackMachineClass",
+								Name: "test-machine-class",
+							},
+						},
+					},
+					3,
+					500,
+					nil,
+					nil,
+					map[string]string{
+						PreferNoScheduleKey: "True",
+					},
+					nil,
+				)[0],
+				expect: expect{
+					machineSets: newMachineSets(
+						1,
+						&machinev1.MachineTemplateSpec{
+							ObjectMeta: *newObjectMeta(objMeta, 0),
+							Spec: machinev1.MachineSpec{
+								Class: machinev1.ClassSpec{
+									Kind: "OpenStackMachineClass",
+									Name: "test-machine-class",
+								},
+							},
+						},
+						3,
+						500,
+						nil,
+						nil,
+						map[string]string{},
+						nil,
+					),
+					nodes: newNodes(
+						1,
+						nil,
+						&corev1.NodeSpec{
+							Taints: []corev1.Taint{},
+						},
+						nil,
+					),
+					err: false,
+				},
+			}),
+		)
+	})
 })
diff --git a/pkg/controller/machineset_test.go b/pkg/controller/machineset_test.go
index 3bdd70c23..a9fbc9d8c 100644
--- a/pkg/controller/machineset_test.go
+++ b/pkg/controller/machineset_test.go
@@ -17,7 +17,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/client-go/testing"
-	"k8s.io/utils/pointer"
+	"k8s.io/utils/ptr"
 
 	machinev1 "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1"
 	faketyped "github.com/gardener/machine-controller-manager/pkg/client/clientset/versioned/typed/machine/v1alpha1/fake"
@@ -181,7 +181,7 @@ var _ = Describe("machineset", func() {
 							Kind:       "MachineSet",
 							Name:       "MachineSet-test",
 							UID:        "1234567",
-							Controller: pointer.Bool(true),
+							Controller: ptr.To(true),
 						},
 					},
 				},
@@ -318,7 +318,7 @@ var _ = Describe("machineset", func() {
 							Kind:       "MachineSet",
 							Name:       "MachineSet-test",
 							UID:        "1234567",
-							Controller: pointer.Bool(true),
+							Controller: ptr.To(true),
 						},
 					},
 				},
@@ -397,7 +397,7 @@ var _ = Describe("machineset", func() {
 								Kind:       "MachineSet",
 								Name:       "MachineSet-test",
 								UID:        "1234567",
-								Controller: pointer.Bool(true),
+								Controller: ptr.To(true),
 							},
 						},
 					},
@@ -450,7 +450,7 @@ var _ = Describe("machineset", func() {
 							Kind:       "MachineSet",
 							Name:       "MachineSet-test-dummy",
 							UID:        "1234567",
-							Controller: pointer.Bool(true),
+							Controller: ptr.To(true),
 						},
 					}
 				},
@@ -727,7 +727,7 @@ var _ = Describe("machineset", func() {
 			activeMachines := []*machinev1.Machine{testActiveMachine1, testActiveMachine2}
 
 			testMachineSet.TypeMeta = metav1.TypeMeta{}
-			Err := c.manageReplicas(context.Background(), activeMachines, testMachineSet)
+			Err := c.manageReplicas(context.TODO(), activeMachines, testMachineSet)
 			waitForCacheSync(stop, c)
 
 			Expect(Err).Should(BeNil())
@@ -747,7 +747,7 @@ var _ = Describe("machineset", func() {
 			waitForCacheSync(stop, c)
 
 			activeMachines := []*machinev1.Machine{testActiveMachine1, testActiveMachine2}
-			Expect(c.manageReplicas(context.Background(), activeMachines, testMachineSet)).NotTo(HaveOccurred())
+			Expect(c.manageReplicas(context.TODO(), activeMachines, testMachineSet)).NotTo(HaveOccurred())
 			waitForCacheSync(stop, c)
 			// TODO: Could not use Listers here, need to check more.
 			machines, err := c.controlMachineClient.Machines(testNamespace).List(context.Background(), metav1.ListOptions{})
@@ -837,7 +837,7 @@ var _ = Describe("machineset", func() {
 			Expect(len(machines.Items)).To(Equal(int(testMachineSet.Spec.Replicas + 1)))
 
 			activeMachines := []*machinev1.Machine{testActiveMachine1, testActiveMachine2, testActiveMachine3, testActiveMachine4}
-			Err := c.manageReplicas(context.Background(), activeMachines, testMachineSet)
+			Err := c.manageReplicas(context.TODO(), activeMachines, testMachineSet)
 			waitForCacheSync(stop, c)
 			machines, _ = c.controlMachineClient.Machines(testNamespace).List(context.Background(), metav1.ListOptions{})
 			Expect(len(machines.Items)).To(Equal(int(testMachineSet.Spec.Replicas)))
diff --git a/pkg/test/integration/common/helpers/cluster.go b/pkg/test/integration/common/helpers/cluster.go
index 88c4cb91f..2d4210e5a 100644
--- a/pkg/test/integration/common/helpers/cluster.go
+++ b/pkg/test/integration/common/helpers/cluster.go
@@ -7,6 +7,7 @@ package helpers
 import (
 	"context"
 	"fmt"
+	"maps"
 
 	mcmClientset "github.com/gardener/machine-controller-manager/pkg/client/clientset/versioned"
 	v1 "k8s.io/api/core/v1"
@@ -89,13 +90,11 @@ func (c *Cluster) GetSecretData(machineClassName string, secretRefs ...*v1.Secre
 	return secretData, nil
 }
 
-func mergeDataMaps(in map[string][]byte, maps ...map[string][]byte) map[string][]byte {
+func mergeDataMaps(in map[string][]byte, dataMaps ...map[string][]byte) map[string][]byte {
 	out := make(map[string][]byte)
 
-	for _, m := range append([]map[string][]byte{in}, maps...) {
-		for k, v := range m {
-			out[k] = v
-		}
+	for _, m := range append([]map[string][]byte{in}, dataMaps...) {
+		maps.Copy(out, m)
 	}
 
 	return out
diff --git a/pkg/test/integration/common/helpers/handling_files.go b/pkg/test/integration/common/helpers/handling_files.go
index 76bf4d99c..0b1f7b41c 100644
--- a/pkg/test/integration/common/helpers/handling_files.go
+++ b/pkg/test/integration/common/helpers/handling_files.go
@@ -172,7 +172,7 @@ func (c *Cluster) applyFile(filePath string, namespace string) error {
 
 // checkEstablished uses the specified name to check if it is established
 func (c *Cluster) checkEstablished(crdName string) error {
-	err := wait.Poll(500*time.Millisecond, 60*time.Second, func() (bool, error) {
+	err := wait.PollUntilContextTimeout(context.Background(), 500*time.Millisecond, 60*time.Second, false, func(_ context.Context) (bool, error) {
 		crd, err := c.apiextensionsClient.
 			ApiextensionsV1().
 			CustomResourceDefinitions().
diff --git a/pkg/test/utils/matchers/deep.go b/pkg/test/utils/matchers/deep.go
index 72acf2f90..2c2904c51 100644
--- a/pkg/test/utils/matchers/deep.go
+++ b/pkg/test/utils/matchers/deep.go
@@ -21,11 +21,11 @@ This is to avoid mistakes where both sides of an assertion are erroneously unini
 
 type deepMatcher struct {
 	name      string
-	expected  interface{}
-	compareFn func(a1, a2 interface{}) bool
+	expected  any
+	compareFn func(a1, a2 any) bool
 }
 
-func newDeepDerivativeMatcher(expected interface{}) gomegatypes.GomegaMatcher {
+func newDeepDerivativeMatcher(expected any) gomegatypes.GomegaMatcher {
 	return &deepMatcher{
 		name:      "deep derivative equal",
 		expected:  expected,
@@ -33,7 +33,7 @@ func newDeepDerivativeMatcher(expected interface{}) gomegatypes.GomegaMatcher {
 	}
 }
 
-func newDeepEqualMatcher(expected interface{}) gomegatypes.GomegaMatcher {
+func newDeepEqualMatcher(expected any) gomegatypes.GomegaMatcher {
 	return &deepMatcher{
 		name:      "deep equal",
 		expected:  expected,
@@ -41,7 +41,7 @@ func newDeepEqualMatcher(expected interface{}) gomegatypes.GomegaMatcher {
 	}
 }
 
-func (m *deepMatcher) Match(actual interface{}) (success bool, err error) {
+func (m *deepMatcher) Match(actual any) (success bool, err error) {
 	if actual == nil && m.expected == nil {
 		return false, fmt.Errorf("%s", deepMatcherNilError)
 	}
@@ -49,15 +49,15 @@ func (m *deepMatcher) Match(actual interface{}) (success bool, err error) {
 	return m.compareFn(m.expected, actual), nil
 }
 
-func (m *deepMatcher) FailureMessage(actual interface{}) (message string) {
+func (m *deepMatcher) FailureMessage(actual any) (message string) {
 	return m.failureMessage(actual, "to")
 }
 
-func (m *deepMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+func (m *deepMatcher) NegatedFailureMessage(actual any) (message string) {
 	return m.failureMessage(actual, "not to")
 }
 
-func (m *deepMatcher) failureMessage(actual interface{}, messagePrefix string) (message string) {
+func (m *deepMatcher) failureMessage(actual any, messagePrefix string) (message string) {
 	var (
 		actualYAML, actualErr     = yaml.Marshal(actual)
 		expectedYAML, expectedErr = yaml.Marshal(m.expected)
diff --git a/pkg/test/utils/matchers/kubernetes_errors.go b/pkg/test/utils/matchers/kubernetes_errors.go
index aebdb20fd..5e35bcfca 100644
--- a/pkg/test/utils/matchers/kubernetes_errors.go
+++ b/pkg/test/utils/matchers/kubernetes_errors.go
@@ -15,7 +15,7 @@ type kubernetesErrors struct {
 	message   string
 }
 
-func (k *kubernetesErrors) Match(actual interface{}) (success bool, err error) {
+func (k *kubernetesErrors) Match(actual any) (success bool, err error) {
 	// is purely nil?
 	if actual == nil {
 		return false, nil
@@ -29,9 +29,9 @@ func (k *kubernetesErrors) Match(actual interface{}) (success bool, err error) {
 	return k.checkFunc(actualErr), nil
 }
 
-func (k *kubernetesErrors) FailureMessage(actual interface{}) (message string) {
+func (k *kubernetesErrors) FailureMessage(actual any) (message string) {
 	return format.Message(actual, fmt.Sprintf("to be %s error", k.message))
 }
-func (k *kubernetesErrors) NegatedFailureMessage(actual interface{}) (message string) {
+func (k *kubernetesErrors) NegatedFailureMessage(actual any) (message string) {
 	return format.Message(actual, fmt.Sprintf("to not be %s error", k.message))
 }
diff --git a/pkg/test/utils/matchers/matchers.go b/pkg/test/utils/matchers/matchers.go
index 261fe624a..6fb723371 100644
--- a/pkg/test/utils/matchers/matchers.go
+++ b/pkg/test/utils/matchers/matchers.go
@@ -24,14 +24,14 @@ func init() {
 
 // DeepEqual returns a Gomega matcher which checks whether the expected object is deeply equal with the object it is
 // being compared against.
-func DeepEqual(expected interface{}) types.GomegaMatcher {
+func DeepEqual(expected any) types.GomegaMatcher {
 	return newDeepEqualMatcher(expected)
 }
 
 // DeepDerivativeEqual is similar to DeepEqual except that unset fields in actual are
 // ignored (not compared). This allows us to focus on the fields that matter to
 // the semantic comparison.
-func DeepDerivativeEqual(expected interface{}) types.GomegaMatcher {
+func DeepDerivativeEqual(expected any) types.GomegaMatcher {
 	return newDeepDerivativeMatcher(expected)
 }
 
diff --git a/pkg/util/configz/configz_test.go b/pkg/util/configz/configz_test.go
index c0ffe01e1..2b276ab6b 100644
--- a/pkg/util/configz/configz_test.go
+++ b/pkg/util/configz/configz_test.go
@@ -22,7 +22,7 @@ Modifications Copyright SAP SE or an SAP affiliate company and Gardener contribu
 package configz
 
 import (
-	"io/ioutil"
+	"io"
 	"net/http"
 	"net/http/httptest"
 	"testing"
@@ -44,7 +44,7 @@ func TestConfigz(t *testing.T) {
 		t.Fatalf("err: %v", err)
 	}
 
-	body, err := ioutil.ReadAll(resp.Body)
+	body, err := io.ReadAll(resp.Body)
 	if err != nil {
 		t.Fatalf("err: %v", err)
 	}
@@ -58,7 +58,7 @@ func TestConfigz(t *testing.T) {
 		t.Fatalf("err: %v", err)
 	}
 
-	body, err = ioutil.ReadAll(resp.Body)
+	body, err = io.ReadAll(resp.Body)
 	if err != nil {
 		t.Fatalf("err: %v", err)
 	}
@@ -72,7 +72,7 @@ func TestConfigz(t *testing.T) {
 		t.Fatalf("err: %v", err)
 	}
 
-	body, err = ioutil.ReadAll(resp.Body)
+	body, err = io.ReadAll(resp.Body)
 	if err != nil {
 		t.Fatalf("err: %v", err)
 	}
diff --git a/pkg/util/hash/hash_test.go b/pkg/util/hash/hash_test.go
index 190afa9e2..3e35ef67b 100644
--- a/pkg/util/hash/hash_test.go
+++ b/pkg/util/hash/hash_test.go
@@ -49,22 +49,22 @@ func (c C) String() string {
 }
 
 func TestDeepHashObject(t *testing.T) {
-	successCases := []func() interface{}{
-		func() interface{} { return 8675309 },
-		func() interface{} { return "Jenny, I got your number" },
-		func() interface{} { return []string{"eight", "six", "seven"} },
-		func() interface{} { return [...]int{5, 3, 0, 9} },
-		func() interface{} { return map[int]string{8: "8", 6: "6", 7: "7"} },
-		func() interface{} { return map[string]int{"5": 5, "3": 3, "0": 0, "9": 9} },
-		func() interface{} { return A{867, "5309"} },
-		func() interface{} { return &A{867, "5309"} },
-		func() interface{} {
+	successCases := []func() any{
+		func() any { return 8675309 },
+		func() any { return "Jenny, I got your number" },
+		func() any { return []string{"eight", "six", "seven"} },
+		func() any { return [...]int{5, 3, 0, 9} },
+		func() any { return map[int]string{8: "8", 6: "6", 7: "7"} },
+		func() any { return map[string]int{"5": 5, "3": 3, "0": 0, "9": 9} },
+		func() any { return A{867, "5309"} },
+		func() any { return &A{867, "5309"} },
+		func() any {
 			return B{[]int{8, 6, 7}, map[string]bool{"5": true, "3": true, "0": true, "9": true}}
 		},
-		func() interface{} { return map[A]bool{{8675309, "Jenny"}: true, {9765683, "!Jenny"}: false} },
-		func() interface{} { return map[C]bool{{8675309, "Jenny"}: true, {9765683, "!Jenny"}: false} },
-		func() interface{} { return map[*A]bool{{8675309, "Jenny"}: true, {9765683, "!Jenny"}: false} },
-		func() interface{} { return map[*C]bool{{8675309, "Jenny"}: true, {9765683, "!Jenny"}: false} },
+		func() any { return map[A]bool{{8675309, "Jenny"}: true, {9765683, "!Jenny"}: false} },
+		func() any { return map[C]bool{{8675309, "Jenny"}: true, {9765683, "!Jenny"}: false} },
+		func() any { return map[*A]bool{{8675309, "Jenny"}: true, {9765683, "!Jenny"}: false} },
+		func() any { return map[*C]bool{{8675309, "Jenny"}: true, {9765683, "!Jenny"}: false} },
 	}
 
 	for _, tc := range successCases {
@@ -76,7 +76,7 @@ func TestDeepHashObject(t *testing.T) {
 		if hash1 != hash2 {
 			t.Fatalf("hash of the same object (%q) produced different results: %d vs %d", toString(tc()), hash1, hash2)
 		}
-		for i := 0; i < 100; i++ {
+		for range 100 {
 			hasher2 := adler32.New()
 
 			DeepHashObject(hasher1, tc())
@@ -97,7 +97,7 @@ func TestDeepHashObject(t *testing.T) {
 	}
 }
 
-func toString(obj interface{}) string {
+func toString(obj any) string {
 	return spew.Sprintf("%#v", obj)
 }
 
@@ -122,7 +122,7 @@ func TestDeepObjectPointer(t *testing.T) {
 	myUni3 := unicycle{licencePlateID: "blah", primaryWheel: &wheel3, tags: map[string]string{"color": "blue", "name": "john"}}
 
 	// Run it more than once to verify determinism of hasher.
-	for i := 0; i < 100; i++ {
+	for range 100 {
 		hasher1 := adler32.New()
 		hasher2 := adler32.New()
 		hasher3 := adler32.New()
diff --git a/pkg/util/provider/drain/drain_test.go b/pkg/util/provider/drain/drain_test.go
index 0161cc7fd..2cd8f9966 100644
--- a/pkg/util/provider/drain/drain_test.go
+++ b/pkg/util/provider/drain/drain_test.go
@@ -1033,7 +1033,7 @@ func getPodWithPV(ns, name, exclusivePV, sharedPV, nodeName string, terminationG
 	}
 
 	if exclusivePV != "" {
-		for i := 0; i < numberOfExclusivePVs; i++ {
+		for i := range numberOfExclusivePVs {
 			appendVolume(pod, exclusivePV+"-"+strconv.Itoa(i))
 		}
 	}
diff --git a/pkg/util/provider/machinecontroller/controller_suite_test.go b/pkg/util/provider/machinecontroller/controller_suite_test.go
index f0e94db7c..6d6366f6a 100644
--- a/pkg/util/provider/machinecontroller/controller_suite_test.go
+++ b/pkg/util/provider/machinecontroller/controller_suite_test.go
@@ -28,7 +28,6 @@ import (
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
-	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/apimachinery/pkg/util/sets"
 	"k8s.io/apimachinery/pkg/watch"
 	coreinformers "k8s.io/client-go/informers"
@@ -36,7 +35,6 @@ import (
 	"k8s.io/client-go/tools/record"
 	"k8s.io/client-go/util/workqueue"
 	"k8s.io/klog/v2"
-	"k8s.io/utils/ptr"
 )
 
 func TestMachineControllerSuite(t *testing.T) {
@@ -58,249 +56,6 @@ var _ = BeforeSuite(func() {
 	DeferCleanup(klog.Flush)
 })
 
-var (
-	controllerKindMachine = v1alpha1.SchemeGroupVersion.WithKind("Machine")
-	MachineClass          = "MachineClass"
-	TestMachineClass      = "machineClass-0"
-)
-
-func newMachineDeployment(
-	specTemplate *v1alpha1.MachineTemplateSpec,
-	replicas int32,
-	minReadySeconds int32,
-	statusTemplate *v1alpha1.MachineDeploymentStatus,
-	owner *metav1.OwnerReference,
-	annotations map[string]string,
-	labels map[string]string,
-) *v1alpha1.MachineDeployment {
-	return newMachineDeployments(1, specTemplate, replicas, minReadySeconds, statusTemplate, owner, annotations, labels)[0]
-}
-
-func newMachineDeployments(
-	machineDeploymentCount int,
-	specTemplate *v1alpha1.MachineTemplateSpec,
-	replicas int32,
-	minReadySeconds int32,
-	statusTemplate *v1alpha1.MachineDeploymentStatus,
-	owner *metav1.OwnerReference,
-	annotations map[string]string,
-	labels map[string]string,
-) []*v1alpha1.MachineDeployment {
-
-	intStr1 := intstr.FromInt(1)
-	machineDeployments := make([]*v1alpha1.MachineDeployment, machineDeploymentCount)
-	for i := range machineDeployments {
-		machineDeployment := &v1alpha1.MachineDeployment{
-			TypeMeta: metav1.TypeMeta{
-				APIVersion: "machine.sapcloud.io",
-				Kind:       "MachineDeployment",
-			},
-			ObjectMeta: metav1.ObjectMeta{
-				Name:      fmt.Sprintf("machinedeployment-%d", i),
-				Namespace: testNamespace,
-				Labels:    labels,
-			},
-			Spec: v1alpha1.MachineDeploymentSpec{
-				MinReadySeconds: minReadySeconds,
-				Replicas:        replicas,
-				Selector: &metav1.LabelSelector{
-					MatchLabels: deepCopy(specTemplate.ObjectMeta.Labels),
-				},
-				Strategy: v1alpha1.MachineDeploymentStrategy{
-					RollingUpdate: &v1alpha1.RollingUpdateMachineDeployment{
-						UpdateConfiguration: v1alpha1.UpdateConfiguration{
-							MaxSurge:       &intStr1,
-							MaxUnavailable: &intStr1,
-						},
-					},
-				},
-				Template: *specTemplate.DeepCopy(),
-			},
-		}
-
-		if statusTemplate != nil {
-			machineDeployment.Status = *statusTemplate.DeepCopy()
-		}
-
-		if owner != nil {
-			machineDeployment.OwnerReferences = append(machineDeployment.OwnerReferences, *owner.DeepCopy())
-		}
-
-		if annotations != nil {
-			machineDeployment.Annotations = annotations
-		}
-
-		machineDeployments[i] = machineDeployment
-	}
-	return machineDeployments
-}
-
-func newMachineSetFromMachineDeployment(
-	machineDeployment *v1alpha1.MachineDeployment,
-	replicas int32,
-	statusTemplate *v1alpha1.MachineSetStatus,
-	annotations map[string]string,
-	labels map[string]string,
-) *v1alpha1.MachineSet {
-	return newMachineSetsFromMachineDeployment(1, machineDeployment, replicas, statusTemplate, annotations, labels)[0]
-}
-
-func newMachineSetsFromMachineDeployment(
-	machineSetCount int,
-	machineDeployment *v1alpha1.MachineDeployment,
-	replicas int32,
-	statusTemplate *v1alpha1.MachineSetStatus,
-	annotations map[string]string,
-	labels map[string]string,
-) []*v1alpha1.MachineSet {
-
-	finalLabels := make(map[string]string)
-	for k, v := range labels {
-		finalLabels[k] = v
-	}
-	for k, v := range machineDeployment.Spec.Template.Labels {
-		finalLabels[k] = v
-	}
-
-	t := &machineDeployment.TypeMeta
-
-	return newMachineSets(
-		machineSetCount,
-		&machineDeployment.Spec.Template,
-		replicas,
-		machineDeployment.Spec.MinReadySeconds,
-		statusTemplate,
-		&metav1.OwnerReference{
-			APIVersion:         t.APIVersion,
-			Kind:               t.Kind,
-			Name:               machineDeployment.Name,
-			UID:                machineDeployment.UID,
-			BlockOwnerDeletion: ptr.To(true),
-			Controller:         ptr.To(true),
-		},
-		annotations,
-		finalLabels,
-	)
-}
-
-func newMachineSet(
-	specTemplate *v1alpha1.MachineTemplateSpec,
-	replicas int32,
-	minReadySeconds int32,
-	statusTemplate *v1alpha1.MachineSetStatus,
-	owner *metav1.OwnerReference,
-	annotations map[string]string,
-	labels map[string]string,
-) *v1alpha1.MachineSet {
-	return newMachineSets(1, specTemplate, replicas, minReadySeconds, statusTemplate, owner, annotations, labels)[0]
-}
-
-func newMachineSets(
-	machineSetCount int,
-	specTemplate *v1alpha1.MachineTemplateSpec,
-	replicas int32,
-	minReadySeconds int32,
-	statusTemplate *v1alpha1.MachineSetStatus,
-	owner *metav1.OwnerReference,
-	annotations map[string]string,
-	labels map[string]string,
-) []*v1alpha1.MachineSet {
-
-	machineSets := make([]*v1alpha1.MachineSet, machineSetCount)
-	for i := range machineSets {
-		ms := &v1alpha1.MachineSet{
-			TypeMeta: metav1.TypeMeta{
-				APIVersion: "machine.sapcloud.io",
-				Kind:       "MachineSet",
-			},
-			ObjectMeta: metav1.ObjectMeta{
-				Name:      fmt.Sprintf("machineset-%d", i),
-				Namespace: testNamespace,
-				Labels:    labels,
-			},
-			Spec: v1alpha1.MachineSetSpec{
-				MachineClass:    *specTemplate.Spec.Class.DeepCopy(),
-				MinReadySeconds: minReadySeconds,
-				Replicas:        replicas,
-				Selector: &metav1.LabelSelector{
-					MatchLabels: deepCopy(specTemplate.ObjectMeta.Labels),
-				},
-				Template: *specTemplate.DeepCopy(),
-			},
-		}
-
-		if statusTemplate != nil {
-			ms.Status = *statusTemplate.DeepCopy()
-		}
-
-		if owner != nil {
-			ms.OwnerReferences = append(ms.OwnerReferences, *owner.DeepCopy())
-		}
-
-		if annotations != nil {
-			ms.Annotations = annotations
-		}
-
-		machineSets[i] = ms
-	}
-	return machineSets
-}
-
-func deepCopy(m map[string]string) map[string]string {
-	r := make(map[string]string, len(m))
-	for k := range m {
-		r[k] = m[k]
-	}
-	return r
-}
-
-func newMachineFromMachineSet(
-	machineSet *v1alpha1.MachineSet,
-	statusTemplate *v1alpha1.MachineStatus,
-	annotations map[string]string,
-	labels map[string]string,
-	addFinalizer bool,
-) *v1alpha1.Machine {
-	return newMachinesFromMachineSet(1, machineSet, statusTemplate, annotations, labels, addFinalizer)[0]
-}
-
-func newMachinesFromMachineSet(
-	machineCount int,
-	machineSet *v1alpha1.MachineSet,
-	statusTemplate *v1alpha1.MachineStatus,
-	annotations map[string]string,
-	labels map[string]string,
-	addFinalizer bool,
-) []*v1alpha1.Machine {
-	t := &machineSet.TypeMeta
-
-	finalLabels := make(map[string]string, 0)
-	for k, v := range labels {
-		finalLabels[k] = v
-	}
-	for k, v := range machineSet.Spec.Template.Labels {
-		finalLabels[k] = v
-	}
-
-	return newMachines(
-		machineCount,
-		&machineSet.Spec.Template,
-		statusTemplate,
-		&metav1.OwnerReference{
-			APIVersion:         t.APIVersion,
-			Kind:               t.Kind,
-			Name:               machineSet.Name,
-			UID:                machineSet.UID,
-			BlockOwnerDeletion: boolPtr(true),
-			Controller:         boolPtr(true),
-		},
-		annotations,
-		finalLabels,
-		addFinalizer,
-		metav1.Now(),
-	)
-}
-
 func newMachine(
 	specTemplate *v1alpha1.MachineTemplateSpec,
 	statusTemplate *v1alpha1.MachineStatus,
@@ -481,10 +236,6 @@ func newSecretReference(meta *metav1.ObjectMeta, index int) *corev1.SecretRefere
 	return r
 }
 
-func boolPtr(b bool) *bool {
-	return &b
-}
-
 func nodeConditions(kubeletReady, readOnlyFileSystem, networkUnavailable, diskPressure, kernelDeadlock bool) []corev1.NodeCondition {
 	// KernelDeadlock,ReadonlyFilesystem,DiskPressure,NetworkUnavailable
 	conditions := []corev1.NodeCondition{
@@ -580,27 +331,48 @@ func createController(
 	}
 
 	controller := &controller{
-		namespace:                   namespace,
-		nodeConditions:              "KernelDeadlock,ReadonlyFilesystem,DiskPressure,NetworkUnavailable",
-		driver:                      fakedriver,
-		safetyOptions:               safetyOptions,
-		machineClassLister:          machineClass.Lister(),
-		machineClassSynced:          machineClass.Informer().HasSynced,
-		controlCoreClient:           fakeControlCoreClient,
-		controlMachineClient:        fakeTypedMachineClient,
-		internalExternalScheme:      internalExternalScheme,
-		secretLister:                secrets.Lister(),
-		machineLister:               machines.Lister(),
-		machineSynced:               machines.Informer().HasSynced,
-		secretSynced:                secrets.Informer().HasSynced,
-		machineClassQueue:           workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "machineclass"),
-		secretQueue:                 workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "secret"),
-		nodeQueue:                   workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "node"),
-		machineQueue:                workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "machine"),
-		machineTerminationQueue:     workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "machinetermination"),
-		machineSafetyOrphanVMsQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "machinesafetyorphanvms"),
-		machineSafetyAPIServerQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "machinesafetyapiserver"),
-		recorder:                    record.NewBroadcaster().NewRecorder(nil, corev1.EventSource{Component: ""}),
+		namespace:              namespace,
+		nodeConditions:         "KernelDeadlock,ReadonlyFilesystem,DiskPressure,NetworkUnavailable",
+		driver:                 fakedriver,
+		safetyOptions:          safetyOptions,
+		machineClassLister:     machineClass.Lister(),
+		machineClassSynced:     machineClass.Informer().HasSynced,
+		controlCoreClient:      fakeControlCoreClient,
+		controlMachineClient:   fakeTypedMachineClient,
+		internalExternalScheme: internalExternalScheme,
+		secretLister:           secrets.Lister(),
+		machineLister:          machines.Lister(),
+		machineSynced:          machines.Informer().HasSynced,
+		secretSynced:           secrets.Informer().HasSynced,
+		machineClassQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
+			workqueue.DefaultTypedControllerRateLimiter[string](),
+			workqueue.TypedRateLimitingQueueConfig[string]{Name: "machineclass"},
+		),
+		secretQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
+			workqueue.DefaultTypedControllerRateLimiter[string](),
+			workqueue.TypedRateLimitingQueueConfig[string]{Name: "secret"},
+		),
+		nodeQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
+			workqueue.DefaultTypedControllerRateLimiter[string](),
+			workqueue.TypedRateLimitingQueueConfig[string]{Name: "node"},
+		),
+		machineQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
+			workqueue.DefaultTypedControllerRateLimiter[string](),
+			workqueue.TypedRateLimitingQueueConfig[string]{Name: "machine"},
+		),
+		machineTerminationQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
+			workqueue.DefaultTypedControllerRateLimiter[string](),
+			workqueue.TypedRateLimitingQueueConfig[string]{Name: "machinetermination"},
+		),
+		machineSafetyOrphanVMsQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
+			workqueue.DefaultTypedControllerRateLimiter[string](),
+			workqueue.TypedRateLimitingQueueConfig[string]{Name: "machinesafetyorphanvms"},
+		),
+		machineSafetyAPIServerQueue: workqueue.NewTypedRateLimitingQueueWithConfig(
+			workqueue.DefaultTypedControllerRateLimiter[string](),
+			workqueue.TypedRateLimitingQueueConfig[string]{Name: "machinesafetyapiserver"},
+		),
+		recorder: record.NewBroadcaster().NewRecorder(nil, corev1.EventSource{Component: ""}),
 	}
 
 	if !noTargetCluster {
diff --git a/pkg/util/provider/machinecontroller/machine_test.go b/pkg/util/provider/machinecontroller/machine_test.go
index d293988df..e8534c87a 100644
--- a/pkg/util/provider/machinecontroller/machine_test.go
+++ b/pkg/util/provider/machinecontroller/machine_test.go
@@ -326,7 +326,7 @@ var _ = Describe("machine", func() {
 			secrets      []*corev1.Secret
 		}
 		type expect struct {
-			machineClass interface{}
+			machineClass any
 			secretData   map[string][]byte
 			err          bool
 		}
@@ -3614,6 +3614,361 @@ var _ = Describe("machine", func() {
 		)
 	})
 
+	Describe("#pendingMachineCreationMap tests", func() {
+		type setup struct {
+			secrets             []*corev1.Secret
+			machineClasses      []*v1alpha1.MachineClass
+			machines            []*v1alpha1.Machine
+			nodes               []*corev1.Node
+			fakeResourceActions *customfake.ResourceActions
+			controller          *controller
+			noTargetCluster     bool
+		}
+		type machineActionRequest struct {
+			machine      *v1alpha1.Machine
+			machineClass *v1alpha1.MachineClass
+			secret       *corev1.Secret
+		}
+		type action struct {
+			machine                 string
+			forceDeleteLabelPresent bool
+			fakeMachineStatus       *v1alpha1.MachineStatus
+			fakeDriver              *driver.FakeDriver
+			// These fields are used to change the test scenario (add to pending map, call creation/deletion flow)
+			isCreation bool
+			testFunc   func(setup, machineActionRequest) (machineutils.RetryPeriod, error)
+		}
+		type expect struct {
+			machine                       *v1alpha1.Machine
+			err                           error
+			nodeTerminationConditionIsSet bool
+			nodeDeleted                   bool
+			retry                         machineutils.RetryPeriod
+		}
+		type data struct {
+			setup  setup
+			action action
+			expect expect
+		}
+		objMeta := &metav1.ObjectMeta{
+			GenerateName:      "machine",
+			Namespace:         "test",
+			CreationTimestamp: metav1.Now(),
+		}
+		commonSetup := setup{
+			secrets: []*corev1.Secret{
+				{
+					ObjectMeta: *newObjectMeta(objMeta, 0),
+				},
+			},
+			machineClasses: []*v1alpha1.MachineClass{
+				{
+					ObjectMeta: *newObjectMeta(objMeta, 0),
+					SecretRef:  newSecretReference(objMeta, 0),
+				},
+			},
+			machines: newMachines(
+				1,
+				&v1alpha1.MachineTemplateSpec{
+					ObjectMeta: *newObjectMeta(objMeta, 0),
+					Spec: v1alpha1.MachineSpec{
+						Class: v1alpha1.ClassSpec{
+							Kind: "MachineClass",
+							Name: "machine-0",
+						},
+						ProviderID: "fakeID",
+					},
+				},
+				&v1alpha1.MachineStatus{
+					CurrentStatus: v1alpha1.CurrentStatus{
+						Phase:          v1alpha1.MachineRunning,
+						LastUpdateTime: metav1.Now(),
+					},
+					LastOperation: v1alpha1.LastOperation{
+						Description:    "Machine machine-0 successfully joined the cluster",
+						State:          v1alpha1.MachineStateSuccessful,
+						Type:           v1alpha1.MachineOperationCreate,
+						LastUpdateTime: metav1.Now(),
+					},
+				},
+				nil,
+				map[string]string{
+					machineutils.MachinePriority: "3",
+				},
+				map[string]string{
+					v1alpha1.NodeLabelKey: "fakeID-0",
+				},
+				true,
+				metav1.Now(),
+			),
+		}
+		DescribeTable("##table",
+			func(data *data) {
+				stop := make(chan struct{})
+				defer close(stop)
+
+				machineObjects := []runtime.Object{}
+				for _, o := range data.setup.machineClasses {
+					machineObjects = append(machineObjects, o)
+				}
+				for _, o := range data.setup.machines {
+					machineObjects = append(machineObjects, o)
+				}
+
+				controlCoreObjects := []runtime.Object{}
+				targetCoreObjects := []runtime.Object{}
+
+				for _, o := range data.setup.secrets {
+					controlCoreObjects = append(controlCoreObjects, o)
+				}
+				for _, o := range data.setup.nodes {
+					targetCoreObjects = append(targetCoreObjects, o)
+				}
+
+				fakeDriver := driver.NewFakeDriver(
+					data.action.fakeDriver.VMExists,
+					data.action.fakeDriver.ProviderID,
+					data.action.fakeDriver.NodeName,
+					data.action.fakeDriver.LastKnownState,
+					data.action.fakeDriver.Addresses,
+					data.action.fakeDriver.Err,
+					nil,
+				)
+
+				var trackers *customfake.FakeObjectTrackers
+				data.setup.controller, trackers = createController(stop, objMeta.Namespace, machineObjects, controlCoreObjects, targetCoreObjects, fakeDriver, data.setup.noTargetCluster)
+
+				defer trackers.Stop()
+				waitForCacheSync(stop, data.setup.controller)
+
+				action := data.action
+				machine, err := data.setup.controller.controlMachineClient.Machines(objMeta.Namespace).Get(context.TODO(), action.machine, metav1.GetOptions{})
+				Expect(err).ToNot(HaveOccurred())
+
+				machineClass, err := data.setup.controller.controlMachineClient.MachineClasses(objMeta.Namespace).Get(context.TODO(), machine.Spec.Class.Name, metav1.GetOptions{})
+				Expect(err).ToNot(HaveOccurred())
+
+				secret, err := data.setup.controller.controlCoreClient.CoreV1().Secrets(objMeta.Namespace).Get(context.TODO(), machineClass.SecretRef.Name, metav1.GetOptions{})
+				Expect(err).ToNot(HaveOccurred())
+
+				if data.setup.fakeResourceActions != nil {
+					_ = trackers.TargetCore.SetFakeResourceActions(data.setup.fakeResourceActions, math.MaxInt32)
+				}
+
+				// ******************************************************
+				// This is changing the setup in accordance with the test
+				retry, err := data.action.testFunc(data.setup, machineActionRequest{
+					machine:      machine,
+					machineClass: machineClass,
+					secret:       secret,
+				})
+				// ******************************************************
+
+				if err != nil || data.expect.err != nil {
+					Expect(err).To(Equal(data.expect.err))
+				}
+				Expect(retry).To(Equal(data.expect.retry))
+
+				if data.action.isCreation {
+					_, found := data.setup.controller.pendingMachineCreationMap.Load(data.expect.machine.Name)
+					Expect(found).To(Equal(false))
+				}
+
+				machine, err = data.setup.controller.controlMachineClient.Machines(objMeta.Namespace).Get(context.TODO(), action.machine, metav1.GetOptions{})
+				Expect(err).ToNot(HaveOccurred())
+				Expect(machine.Spec).To(Equal(data.expect.machine.Spec))
+				Expect(machine.Status.CurrentStatus.Phase).To(Equal(data.expect.machine.Status.CurrentStatus.Phase))
+				Expect(machine.Status.LastOperation.State).To(Equal(data.expect.machine.Status.LastOperation.State))
+				Expect(machine.Status.LastOperation.Type).To(Equal(data.expect.machine.Status.LastOperation.Type))
+				Expect(machine.Status.LastOperation.Description).To(Equal(data.expect.machine.Status.LastOperation.Description))
+				Expect(machine.Finalizers).To(Equal(data.expect.machine.Finalizers))
+
+				if data.expect.nodeDeleted {
+					_, nodeErr := data.setup.controller.targetCoreClient.CoreV1().Nodes().Get(context.TODO(), machine.Labels[v1alpha1.NodeLabelKey], metav1.GetOptions{})
+					Expect(nodeErr).To(HaveOccurred())
+				}
+				if data.expect.nodeTerminationConditionIsSet {
+					node, nodeErr := data.setup.controller.targetCoreClient.CoreV1().Nodes().Get(context.TODO(), machine.Labels[v1alpha1.NodeLabelKey], metav1.GetOptions{})
+					Expect(nodeErr).To(Not(HaveOccurred()))
+					Expect(len(node.Status.Conditions)).To(Equal(1))
+					Expect(node.Status.Conditions[0].Type).To(Equal(machineutils.NodeTerminationCondition))
+					Expect(node.Status.Conditions[0].Status).To(Equal(corev1.ConditionTrue))
+				}
+			},
+			Entry("Remove machine from pendingMachineCreationMap after it exits creation flow", &data{
+				setup: setup{
+					secrets: []*corev1.Secret{
+						{
+							ObjectMeta: *newObjectMeta(objMeta, 0),
+							Data:       map[string][]byte{"userData": []byte("test")},
+						},
+					},
+					machineClasses: []*v1alpha1.MachineClass{
+						{
+							ObjectMeta: *newObjectMeta(objMeta, 0),
+							SecretRef:  newSecretReference(objMeta, 0),
+						},
+					},
+					machines: newMachines(1, &v1alpha1.MachineTemplateSpec{
+						ObjectMeta: *newObjectMeta(objMeta, 0),
+						Spec: v1alpha1.MachineSpec{
+							Class: v1alpha1.ClassSpec{
+								Kind: "MachineClass",
+								Name: "machine-0",
+							},
+						},
+					}, nil, nil, nil, nil, true, metav1.Now()),
+				},
+				action: action{
+					machine: "machine-0",
+					fakeDriver: &driver.FakeDriver{
+						VMExists:   true,
+						ProviderID: "fakeID-0",
+						NodeName:   "fakeNode-0",
+						Err:        nil,
+					},
+					isCreation: true,
+					testFunc: func(setUp setup, req machineActionRequest) (machineutils.RetryPeriod, error) {
+						return setUp.controller.triggerCreationFlow(context.TODO(), &driver.CreateMachineRequest{
+							Machine:      req.machine,
+							MachineClass: req.machineClass,
+							Secret:       req.secret,
+						})
+					},
+				},
+				expect: expect{
+					machine: newMachine(&v1alpha1.MachineTemplateSpec{
+						ObjectMeta: *newObjectMeta(objMeta, 0),
+						Spec: v1alpha1.MachineSpec{
+							Class: v1alpha1.ClassSpec{
+								Kind: "MachineClass",
+								Name: "machine-0",
+							},
+							ProviderID: "fakeID",
+						},
+					}, nil, nil, nil, map[string]string{v1alpha1.NodeLabelKey: "fakeNode-0"}, true, metav1.Now()),
+					err:   fmt.Errorf("machine creation in process. Machine labels/annotations update is successful"),
+					retry: machineutils.ShortRetry,
+				},
+			}),
+			Entry("Do not process machine deletion for machine present in pendingMachineCreationMap", &data{
+				setup: commonSetup,
+				action: action{
+					machine: "machine-0",
+					fakeDriver: &driver.FakeDriver{
+						VMExists:   true,
+						ProviderID: "fakeID-0",
+						NodeName:   "fakeNode-0",
+						Err:        nil,
+					},
+					isCreation: false,
+					testFunc: func(setUp setup, req machineActionRequest) (machineutils.RetryPeriod, error) {
+						setUp.controller.pendingMachineCreationMap.Store("test/machine-0", "")
+						return setUp.controller.triggerDeletionFlow(context.TODO(), &driver.DeleteMachineRequest{
+							Machine:      req.machine,
+							MachineClass: req.machineClass,
+							Secret:       req.secret,
+						})
+					},
+				},
+				expect: expect{
+					err:   fmt.Errorf("machine \"machine-0\" is in creation flow. Deletion cannot proceed"),
+					retry: machineutils.MediumRetry,
+					machine: newMachine(
+						&v1alpha1.MachineTemplateSpec{
+							ObjectMeta: *newObjectMeta(objMeta, 0),
+							Spec: v1alpha1.MachineSpec{
+								Class: v1alpha1.ClassSpec{
+									Kind: "MachineClass",
+									Name: "machine-0",
+								},
+								ProviderID: "fakeID",
+							},
+						},
+						&v1alpha1.MachineStatus{
+							CurrentStatus: v1alpha1.CurrentStatus{
+								Phase:          v1alpha1.MachineRunning,
+								LastUpdateTime: metav1.Now(),
+							},
+							LastOperation: v1alpha1.LastOperation{
+								Description:    "Machine machine-0 successfully joined the cluster",
+								State:          v1alpha1.MachineStateSuccessful,
+								Type:           v1alpha1.MachineOperationCreate,
+								LastUpdateTime: metav1.Now(),
+							},
+						},
+						nil,
+						map[string]string{
+							machineutils.MachinePriority: "3",
+						},
+						map[string]string{
+							v1alpha1.NodeLabelKey: "fakeID-0",
+						},
+						true,
+						metav1.Now(),
+					),
+				},
+			}),
+			Entry("Proceed with machine deletion for machine not present in pendingMachineCreationMap", &data{
+				setup: commonSetup,
+				action: action{
+					machine: "machine-0",
+					fakeDriver: &driver.FakeDriver{
+						VMExists:   true,
+						ProviderID: "fakeID-0",
+						NodeName:   "fakeNode-0",
+						Err:        nil,
+					},
+					isCreation: false,
+					testFunc: func(setUp setup, req machineActionRequest) (machineutils.RetryPeriod, error) {
+						setUp.controller.pendingMachineCreationMap.Store("machine-xyz", "")
+						return setUp.controller.triggerDeletionFlow(context.TODO(), &driver.DeleteMachineRequest{
+							Machine:      req.machine,
+							MachineClass: req.machineClass,
+							Secret:       req.secret,
+						})
+					},
+				},
+				expect: expect{
+					err:   fmt.Errorf("Machine deletion in process. Phase set to termination"),
+					retry: machineutils.ShortRetry,
+					machine: newMachine(
+						&v1alpha1.MachineTemplateSpec{
+							ObjectMeta: *newObjectMeta(objMeta, 0),
+							Spec: v1alpha1.MachineSpec{
+								Class: v1alpha1.ClassSpec{
+									Kind: "MachineClass",
+									Name: "machine-0",
+								},
+								ProviderID: "fakeID",
+							},
+						},
+						&v1alpha1.MachineStatus{
+							CurrentStatus: v1alpha1.CurrentStatus{
+								Phase:          v1alpha1.MachineTerminating,
+								LastUpdateTime: metav1.Now(),
+							},
+							LastOperation: v1alpha1.LastOperation{
+								Description:    machineutils.GetVMStatus,
+								State:          v1alpha1.MachineStateProcessing,
+								Type:           v1alpha1.MachineOperationDelete,
+								LastUpdateTime: metav1.Now(),
+							},
+						},
+						nil,
+						map[string]string{
+							machineutils.MachinePriority: "3",
+						},
+						map[string]string{
+							v1alpha1.NodeLabelKey: "fakeID-0",
+						},
+						true,
+						metav1.Now(),
+					),
+				},
+			}),
+		)
+	})
 	/*
 		Describe("#checkMachineTimeout", func() {
 			type setup struct {
diff --git a/pkg/util/provider/machinecontroller/userdata_test.go b/pkg/util/provider/machinecontroller/userdata_test.go
index 8b7b62a99..be5e57587 100644
--- a/pkg/util/provider/machinecontroller/userdata_test.go
+++ b/pkg/util/provider/machinecontroller/userdata_test.go
@@ -70,7 +70,7 @@ chmod "0640" "/var/lib/gardener-node-agent/credentials/machine-name"
 		_, tokenSecretName = getTokenIDAndSecretName(machine.Name)
 		userDataSecret = &corev1.Secret{
 			Data: map[string][]byte{
-				"userData": []byte(fmt.Sprintf(userDataTemplate, "<<BOOTSTRAP_TOKEN>>", "<<MACHINE_NAME>>")),
+				"userData": fmt.Appendf(nil, userDataTemplate, "<<BOOTSTRAP_TOKEN>>", "<<MACHINE_NAME>>"),
 			},
 		}
 	})
@@ -78,7 +78,7 @@ chmod "0640" "/var/lib/gardener-node-agent/credentials/machine-name"
 	Describe("#addBootstrapTokenToUserData", func() {
 		It("should generate a bootstrap token replace the magic string with it", func() {
 			Expect(machineController.addBootstrapTokenToUserData(ctx, machine, userDataSecret)).To(Succeed())
-			Expect(userDataSecret.Data["userData"]).To(Equal([]byte(fmt.Sprintf(userDataTemplate, getBootstrapToken(), "<<MACHINE_NAME>>"))))
+			Expect(userDataSecret.Data["userData"]).To(Equal(fmt.Appendf(nil, userDataTemplate, getBootstrapToken(), "<<MACHINE_NAME>>")))
 		})
 
 		It("should do nothing if there is no magic string", func() {
@@ -99,7 +99,7 @@ chmod "0640" "/var/lib/gardener-node-agent/credentials/machine-name"
 
 			It("should not generate a bootstrap token and keep the magic string", func() {
 				Expect(machineController.addBootstrapTokenToUserData(ctx, machine, userDataSecret)).To(Succeed())
-				Expect(userDataSecret.Data["userData"]).To(Equal([]byte(fmt.Sprintf(userDataTemplate, "<<BOOTSTRAP_TOKEN>>", "<<MACHINE_NAME>>"))))
+				Expect(userDataSecret.Data["userData"]).To(Equal(fmt.Appendf(nil, userDataTemplate, "<<BOOTSTRAP_TOKEN>>", "<<MACHINE_NAME>>")))
 			})
 
 			It("should do nothing if there is no magic string", func() {
@@ -113,7 +113,7 @@ chmod "0640" "/var/lib/gardener-node-agent/credentials/machine-name"
 	Describe("#addMachineNameToUserData", func() {
 		It("should replace the magic string with the machine name", func() {
 			Expect(machineController.addMachineNameToUserData(machine, userDataSecret)).To(Succeed())
-			Expect(userDataSecret.Data["userData"]).To(Equal([]byte(fmt.Sprintf(userDataTemplate, "<<BOOTSTRAP_TOKEN>>", machine.Name))))
+			Expect(userDataSecret.Data["userData"]).To(Equal(fmt.Appendf(nil, userDataTemplate, "<<BOOTSTRAP_TOKEN>>", machine.Name)))
 		})
 
 		It("should do nothing if there is no magic string", func() {