Repository: gardener/machine-controller-manager

Issue:
kube-proxy pod not healthy - scale down CA tainted node ASAP
**How to categorize this issue?**
<!--
Please select area, kind, and priority for this issue. This helps the community categorizing it.
Replace below TODOs or exchange the existing identifiers with those that fit best in your opinion.
If multiple identifiers make sense you can also state the commands multiple times, e.g.
  /area control-plane
  /area auto-scaling
  ...

"/area" identifiers:     audit-logging|auto-scaling|backup|certification|control-plane-migration|control-plane|cost|delivery|dev-productivity|disaster-recovery|documentation|high-availability|logging|metering|monitoring|networking|open-source|ops-productivity|os|performance|quality|robustness|scalability|security|storage|testing|usability|user-management
"/kind" identifiers:     api-change|bug|cleanup|discussion|enhancement|epic|impediment|poc|post-mortem|question|regression|task|technical-debt|test
"/priority" identifiers: 1|2|3|4|5 (ordered from greatest to least)
-->
/area auto-scaling
/kind bug
/priority 2

**What happened**:
kube-proxy reports Node as not healthy when CA taints a Node for deletion. MCM does not remove this node if replica count of MachineDeployment is unchanged.

k8s gardener live issue 6101            

**What you expected to happen**:
The machine set controller should mark this node as a stale node and scale it down and scale-up a fresh machine and node to match the replica count.

**How to reproduce it (as minimally and precisely as possible)**:

Taint a k8s node with the CA deletion taint and add the machine name to the triggered for deletion annotation on the machine deployment.

**Anything else we need to know?**:

**Environment**:

- Kubernetes version (use `kubectl version`):
- Cloud provider or hardware configuration:
- Others:


Discussion:
@gardener-robot: @elankath Label area/|auto-scaling does not exist.

Solution patch:
diff --git a/.ci/test b/.ci/test
index d13330b9d..a496c4fec 100755
--- a/.ci/test
+++ b/.ci/test
@@ -36,7 +36,7 @@ function test_with_coverage() {
   local output_dir=test/output
   local coverprofile_file=coverprofile.out
   mkdir -p test/output
-  ginkgo $GINKGO_COMMON_FLAGS --coverprofile ${coverprofile_file} -covermode=set -outputdir ${output_dir} ${TEST_PACKAGES}
+  ginkgo $GINKGO_COMMON_FLAGS --coverprofile ${coverprofile_file} -covermode=set -output-dir ${output_dir} ${TEST_PACKAGES}
 
   sed -i -e '/mode: set/d' ${output_dir}/${coverprofile_file}
   {( echo "mode: set"; cat ${output_dir}/${coverprofile_file} )} > ${output_dir}/${coverprofile_file}.temp
@@ -51,7 +51,7 @@ if [[ "${SKIP_UNIT_TESTS}" != "" ]]; then
 else
   echo ">>>>> Invoking unit tests"
   TEST_PACKAGES="cmd pkg"
-  GINKGO_COMMON_FLAGS="-r -timeout=1h0m0s --randomizeAllSpecs --randomizeSuites --failOnPending  --progress"
+  GINKGO_COMMON_FLAGS="-r -timeout=1h0m0s --randomize-all --randomize-suites --fail-on-pending  --show-node-events"
   test_with_coverage
   echo ">>>>> Finished executing unit tests"
 fi
diff --git a/docs/FAQ.md b/docs/FAQ.md
index b492b5069..b4bbd6de7 100644
--- a/docs/FAQ.md
+++ b/docs/FAQ.md
@@ -1,6 +1,8 @@
 ---
-title: Machine Controller Manager FAQ
+title: FAQ
 description: Commonly asked questions about MCM
+weight: 5
+persona: Operators
 ---
 
 # Frequently Asked Questions
diff --git a/docs/documents/_index.md b/docs/documents/_index.md
new file mode 100644
index 000000000..bdfec1968
--- /dev/null
+++ b/docs/documents/_index.md
@@ -0,0 +1,5 @@
+---
+title: Documents
+weight: 2
+persona: Developers
+---
\ No newline at end of file
diff --git a/docs/proposals/_index.md b/docs/proposals/_index.md
new file mode 100644
index 000000000..970c379bb
--- /dev/null
+++ b/docs/proposals/_index.md
@@ -0,0 +1,5 @@
+---
+title: Proposals
+weight: 3
+persona: Developers
+---
\ No newline at end of file
diff --git a/docs/todo/_index.md b/docs/todo/_index.md
new file mode 100644
index 000000000..930e852f8
--- /dev/null
+++ b/docs/todo/_index.md
@@ -0,0 +1,5 @@
+---
+title: To-Do
+weight: 4
+persona: Developers
+---
\ No newline at end of file
diff --git a/go.mod b/go.mod
index a6969079b..e9a5ce81e 100644
--- a/go.mod
+++ b/go.mod
@@ -7,8 +7,8 @@ require (
 	github.com/cenkalti/backoff/v4 v4.3.0
 	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
 	github.com/google/uuid v1.6.0
-	github.com/onsi/ginkgo/v2 v2.19.0
-	github.com/onsi/gomega v1.33.1
+	github.com/onsi/ginkgo/v2 v2.23.0
+	github.com/onsi/gomega v1.36.2
 	github.com/prometheus/client_golang v1.19.1
 	github.com/spf13/pflag v1.0.5
 	golang.org/x/lint v0.0.0-20210508222113-6edffad5e616
@@ -43,7 +43,7 @@ require (
 	github.com/google/gnostic-models v0.6.8 // indirect
 	github.com/google/go-cmp v0.6.0 // indirect
 	github.com/google/gofuzz v1.2.0 // indirect
-	github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af // indirect
+	github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect
 	github.com/imdario/mergo v0.3.12 // indirect
 	github.com/inconshreveable/mousetrap v1.1.0 // indirect
 	github.com/josharian/intern v1.0.0 // indirect
@@ -58,16 +58,16 @@ require (
 	github.com/prometheus/procfs v0.15.1 // indirect
 	github.com/spf13/cobra v1.8.1 // indirect
 	github.com/x448/float16 v0.8.4 // indirect
-	golang.org/x/mod v0.17.0 // indirect
-	golang.org/x/net v0.26.0 // indirect
+	golang.org/x/mod v0.23.0 // indirect
+	golang.org/x/net v0.35.0 // indirect
 	golang.org/x/oauth2 v0.21.0 // indirect
-	golang.org/x/sync v0.7.0 // indirect
-	golang.org/x/sys v0.21.0 // indirect
-	golang.org/x/term v0.21.0 // indirect
-	golang.org/x/text v0.16.0 // indirect
+	golang.org/x/sync v0.11.0 // indirect
+	golang.org/x/sys v0.30.0 // indirect
+	golang.org/x/term v0.29.0 // indirect
+	golang.org/x/text v0.22.0 // indirect
 	golang.org/x/time v0.3.0 // indirect
-	golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
-	google.golang.org/protobuf v1.34.2 // indirect
+	golang.org/x/tools v0.30.0 // indirect
+	google.golang.org/protobuf v1.36.1 // indirect
 	gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
diff --git a/go.sum b/go.sum
index 4ca168c08..4eee5a452 100644
--- a/go.sum
+++ b/go.sum
@@ -45,8 +45,8 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
 github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM=
-github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
+github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
+github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
@@ -75,10 +75,10 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
-github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
-github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
-github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
-github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
+github.com/onsi/ginkgo/v2 v2.23.0 h1:FA1xjp8ieYDzlgS5ABTpdUDB7wtngggONc8a7ku2NqQ=
+github.com/onsi/ginkgo/v2 v2.23.0/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM=
+github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
+github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -126,32 +126,32 @@ golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPI
 golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
-golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
+golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
-golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
+golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
+golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
 golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
 golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
-golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
+golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
-golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
-golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
+golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
+golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
+golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
-golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
+golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
+golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
 golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
 golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -159,14 +159,14 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
 golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
-golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
+golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
-google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
+google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
+google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
diff --git a/pkg/controller/controller_utils.go b/pkg/controller/controller_utils.go
index 1063199bd..7790fee28 100644
--- a/pkg/controller/controller_utils.go
+++ b/pkg/controller/controller_utils.go
@@ -786,22 +786,6 @@ func (s ActiveMachines) Less(i, j int) bool {
 	return false
 }
 
-// IsMachineActive checks if machine was active
-func IsMachineActive(p *v1alpha1.Machine) bool {
-	if p.Status.CurrentStatus.Phase == v1alpha1.MachineFailed {
-		return false
-	} else if p.Status.CurrentStatus.Phase == v1alpha1.MachineTerminating {
-		return false
-	}
-
-	return true
-}
-
-// IsMachineFailed checks if machine has failed
-func IsMachineFailed(p *v1alpha1.Machine) bool {
-	return p.Status.CurrentStatus.Phase == v1alpha1.MachineFailed
-}
-
 // MachineKey is the function used to get the machine name from machine object
 // ToCheck : as machine-namespace does not matter
 func MachineKey(machine *v1alpha1.Machine) string {
diff --git a/pkg/controller/deployment_util.go b/pkg/controller/deployment_util.go
index 130527697..974f18a02 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/provider/machineutils"
 	"reflect"
 	"sort"
 	"strconv"
@@ -921,7 +922,7 @@ func WaitForMachinesHashPopulated(c v1alpha1listers.MachineSetLister, desiredGen
 func LabelMachinesWithHash(ctx context.Context, machineList *v1alpha1.MachineList, c v1alpha1client.MachineV1alpha1Interface, machineLister v1alpha1listers.MachineLister, namespace, name, hash string) error {
 	for _, machine := range machineList.Items {
 		// Ignore inactive Machines.
-		if !IsMachineActive(&machine) {
+		if !machineutils.IsMachineActive(&machine) {
 			continue
 		}
 		// Only label the machine that doesn't already have the new hash
diff --git a/pkg/controller/machine_safety.go b/pkg/controller/machine_safety.go
index ffe330001..0f17f367f 100644
--- a/pkg/controller/machine_safety.go
+++ b/pkg/controller/machine_safety.go
@@ -9,6 +9,7 @@ import (
 	"context"
 	"fmt"
 
+	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/labels"
 	intstrutil "k8s.io/apimachinery/pkg/util/intstr"
@@ -26,6 +27,10 @@ const (
 	MachineDeploymentStateSync = "MachineDeploymentStateSync"
 	// UnfreezeAnnotation indicates the controllers to unfreeze this object
 	UnfreezeAnnotation = "safety.machine.sapcloud.io/unfreeze"
+	// MachineSetFreezeEvent is recorded when a machineset is frozen
+	MachineSetFreezeEvent = "FrozeMachineSet"
+	// MachineSetUnfreezeEvent is recorded when a machineset is unfrozen
+	MachineSetUnfreezeEvent = "UnfrozeMachineSet"
 )
 
 // reconcileClusterMachineSafetyOvershooting checks all machineSet/machineDeployment
@@ -330,6 +335,7 @@ func (c *controller) freezeMachineSetAndDeployment(ctx context.Context, machineS
 		}
 	}
 
+	c.recorder.Eventf(machineSet, corev1.EventTypeNormal, MachineSetFreezeEvent, "SafetyController: Froze MachineSet %s due to replica overshooting", machineSet.Name)
 	klog.V(2).Infof("SafetyController: Froze MachineSet %q due to overshooting of replicas", machineSet.Name)
 	return nil
 }
@@ -398,6 +404,7 @@ func (c *controller) unfreezeMachineSet(ctx context.Context, machineSet *v1alpha
 		return err
 	}
 
+	c.recorder.Eventf(machineSet, corev1.EventTypeNormal, MachineSetUnfreezeEvent, "SafetyController: Unfroze MachineSet %s", machineSet.Name)
 	klog.V(2).Infof("SafetyController: Unfroze MachineSet %q", machineSet.Name)
 	return nil
 }
diff --git a/pkg/controller/machineset.go b/pkg/controller/machineset.go
index 4176406e5..4cbe27fe0 100644
--- a/pkg/controller/machineset.go
+++ b/pkg/controller/machineset.go
@@ -26,6 +26,7 @@ import (
 	"context"
 	"errors"
 	"fmt"
+	"github.com/gardener/machine-controller-manager/pkg/util/provider/machineutils"
 	"reflect"
 	"sort"
 	"sync"
@@ -337,11 +338,11 @@ func (c *controller) manageReplicas(ctx context.Context, allMachines []*v1alpha1
 	}
 
 	var activeMachines, staleMachines []*v1alpha1.Machine
-	for _, machine := range allMachines {
-		if IsMachineActive(machine) {
-			activeMachines = append(activeMachines, machine)
-		} else if IsMachineFailed(machine) {
-			staleMachines = append(staleMachines, machine)
+	for _, m := range allMachines {
+		if machineutils.IsMachineFailed(m) || machineutils.IsMachineTriggeredForDeletion(m) {
+			staleMachines = append(staleMachines, m)
+		} else if machineutils.IsMachineActive(m) {
+			activeMachines = append(activeMachines, m)
 		}
 	}
 
@@ -685,7 +686,7 @@ func (c *controller) prepareMachineForDeletion(ctx context.Context, targetMachin
 	} else {
 		// successful delete of a Failed phase machine due to unhealthiness for too long, increments staleMachinesRemoved counter
 		// note: call is blocking and thread safe as other worker threads might be updating the counter as well
-		if IsMachineFailed(targetMachine) && targetMachine.Status.LastOperation.Type == v1alpha1.MachineOperationHealthCheck {
+		if machineutils.IsMachineFailed(targetMachine) && targetMachine.Status.LastOperation.Type == v1alpha1.MachineOperationHealthCheck {
 			staleMachinesRemoved.increment()
 		}
 	}
diff --git a/pkg/controller/machineset_util.go b/pkg/controller/machineset_util.go
index 9227af440..69d8ca6c4 100644
--- a/pkg/controller/machineset_util.go
+++ b/pkg/controller/machineset_util.go
@@ -89,7 +89,7 @@ func (c *controller) syncMachinesNodeTemplates(ctx context.Context, machineList
 
 	for _, machine := range machineList {
 		// Ignore inactive Machines.
-		if !IsMachineActive(machine) {
+		if !machineutils.IsMachineActive(machine) {
 			continue
 		}
 
@@ -155,7 +155,7 @@ func (c *controller) syncMachinesConfig(ctx context.Context, machineList []*v1al
 
 	for _, machine := range machineList {
 		// Ignore inactive Machines.
-		if !IsMachineActive(machine) {
+		if !machineutils.IsMachineActive(machine) {
 			continue
 		}
 
diff --git a/pkg/util/provider/machinecontroller/controller.go b/pkg/util/provider/machinecontroller/controller.go
index 7eb26d22f..baeabd5d3 100644
--- a/pkg/util/provider/machinecontroller/controller.go
+++ b/pkg/util/provider/machinecontroller/controller.go
@@ -92,6 +92,7 @@ func NewController(
 		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"),
 		safetyOptions:                 safetyOptions,
@@ -253,6 +254,7 @@ type controller struct {
 	nodeQueue                   workqueue.RateLimitingInterface
 	machineClassQueue           workqueue.RateLimitingInterface
 	machineQueue                workqueue.RateLimitingInterface
+	machineTerminationQueue     workqueue.RateLimitingInterface
 	machineSafetyOrphanVMsQueue workqueue.RateLimitingInterface
 	machineSafetyAPIServerQueue workqueue.RateLimitingInterface
 	// syncs
@@ -279,6 +281,7 @@ func (c *controller) Run(workers int, stopCh <-chan struct{}) {
 	defer c.secretQueue.ShutDown()
 	defer c.machineClassQueue.ShutDown()
 	defer c.machineQueue.ShutDown()
+	defer c.machineTerminationQueue.ShutDown()
 	defer c.machineSafetyOrphanVMsQueue.ShutDown()
 	defer c.machineSafetyAPIServerQueue.ShutDown()
 
@@ -307,6 +310,7 @@ func (c *controller) Run(workers int, stopCh <-chan struct{}) {
 		worker.Run(c.machineClassQueue, "ClusterMachineClass", worker.DefaultMaxRetries, true, c.reconcileClusterMachineClassKey, stopCh, &waitGroup)
 		worker.Run(c.nodeQueue, "ClusterNode", worker.DefaultMaxRetries, true, c.reconcileClusterNodeKey, stopCh, &waitGroup)
 		worker.Run(c.machineQueue, "ClusterMachine", worker.DefaultMaxRetries, true, c.reconcileClusterMachineKey, stopCh, &waitGroup)
+		worker.Run(c.machineTerminationQueue, "ClusterMachineTermination", worker.DefaultMaxRetries, true, c.reconcileClusterMachineTermination, stopCh, &waitGroup)
 		worker.Run(c.machineSafetyOrphanVMsQueue, "ClusterMachineSafetyOrphanVMs", worker.DefaultMaxRetries, true, c.reconcileClusterMachineSafetyOrphanVMs, stopCh, &waitGroup)
 		worker.Run(c.machineSafetyAPIServerQueue, "ClusterMachineAPIServer", worker.DefaultMaxRetries, true, c.reconcileClusterMachineSafetyAPIServer, stopCh, &waitGroup)
 	}
diff --git a/pkg/util/provider/machinecontroller/machine.go b/pkg/util/provider/machinecontroller/machine.go
index 0a58b6d75..d2c73a877 100644
--- a/pkg/util/provider/machinecontroller/machine.go
+++ b/pkg/util/provider/machinecontroller/machine.go
@@ -17,6 +17,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/labels"
 	"k8s.io/apimachinery/pkg/selection"
+	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 	"k8s.io/apimachinery/pkg/util/sets"
 	"k8s.io/client-go/tools/cache"
 	"k8s.io/klog/v2"
@@ -35,7 +36,19 @@ SECTION
 Machine controller - Machine add, update, delete watches
 */
 func (c *controller) addMachine(obj interface{}) {
-	c.enqueueMachine(obj, "handling machine obj ADD event")
+	machine, ok := obj.(*v1alpha1.Machine)
+	if !ok {
+		klog.Errorf("couldn't convert to machine resource from object")
+		return
+	}
+	// 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 {
+		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{}) {
@@ -52,11 +65,27 @@ func (c *controller) updateMachine(oldObj, newObj interface{}) {
 		return
 	}
 
-	c.enqueueMachine(newObj, "handling machine object UPDATE event")
+	if newMachine.DeletionTimestamp != nil {
+		c.enqueueMachineTermination(newMachine, "handling terminating machine object UPDATE event")
+	} else {
+		c.enqueueMachine(newObj, "handling machine object UPDATE event")
+	}
 }
 
 func (c *controller) deleteMachine(obj interface{}) {
-	c.enqueueMachine(obj, "handling machine object DELETE event")
+	machine, ok := obj.(*v1alpha1.Machine)
+	if !ok {
+		tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
+		if !ok {
+			return
+		}
+		machine, ok = tombstone.Obj.(*v1alpha1.Machine)
+		if !ok {
+			utilruntime.HandleError(fmt.Errorf("Tombstone contained object that is not a Machine Deployment %#v", obj))
+			return
+		}
+	}
+	c.enqueueMachineTermination(machine, "handling terminating machine object DELETE event")
 }
 
 // getKeyForObj returns key for object, else returns false
@@ -83,6 +112,27 @@ func (c *controller) enqueueMachineAfter(obj interface{}, after time.Duration, r
 	}
 }
 
+func (c *controller) enqueueMachineTermination(machine *v1alpha1.Machine, reason string) {
+
+	if key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(machine); err != nil {
+		utilruntime.HandleError(fmt.Errorf("Couldn't get key for object %#v: %v", machine, err))
+		return
+	} else {
+		klog.V(3).Infof("Adding machine object to termination queue %q, reason: %s", key, reason)
+		c.machineTerminationQueue.Add(key)
+	}
+}
+
+func (c *controller) enqueueMachineTerminationAfter(machine *v1alpha1.Machine, after time.Duration, reason string) {
+	if key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(machine); err != nil {
+		utilruntime.HandleError(fmt.Errorf("Couldn't get key for object %#v: %v", machine, err))
+		return
+	} else {
+		klog.V(3).Infof("Adding machine object to termination queue %q after %s, reason: %s", key, after, reason)
+		c.machineTerminationQueue.AddAfter(key, after)
+	}
+}
+
 func (c *controller) reconcileClusterMachineKey(key string) error {
 	ctx := context.Background()
 
@@ -101,12 +151,18 @@ func (c *controller) reconcileClusterMachineKey(key string) error {
 		return err
 	}
 
+	if machine.DeletionTimestamp != nil {
+		klog.Errorf("Machine %q should be in machine termination queue", machine.Name)
+		return nil
+	}
+
 	retryPeriod, err := c.reconcileClusterMachine(ctx, machine)
 
 	var reEnqueReason = "periodic reconcile"
 	if err != nil {
 		reEnqueReason = err.Error()
 	}
+
 	c.enqueueMachineAfter(machine, time.Duration(retryPeriod), reEnqueReason)
 
 	return nil
@@ -144,18 +200,6 @@ func (c *controller) reconcileClusterMachine(ctx context.Context, machine *v1alp
 		return retry, err
 	}
 
-	if machine.DeletionTimestamp != nil {
-		// Process a delete event
-		return c.triggerDeletionFlow(
-			ctx,
-			&driver.DeleteMachineRequest{
-				Machine:      machine,
-				MachineClass: machineClass,
-				Secret:       &corev1.Secret{Data: secretData},
-			},
-		)
-	}
-
 	// Add finalizers if not present on machine object
 	retry, err = c.addMachineFinalizers(ctx, machine)
 	if err != nil {
@@ -193,6 +237,58 @@ func (c *controller) reconcileClusterMachine(ctx context.Context, machine *v1alp
 	return machineutils.LongRetry, nil
 }
 
+func (c *controller) reconcileClusterMachineTermination(key string) error {
+	ctx := context.Background()
+
+	_, name, err := cache.SplitMetaNamespaceKey(key)
+	if err != nil {
+		return err
+	}
+
+	machine, err := c.machineLister.Machines(c.namespace).Get(name)
+	if apierrors.IsNotFound(err) {
+		klog.V(4).Infof("Machine %q: Not doing work because it is not found", key)
+		return nil
+	}
+	if err != nil {
+		klog.Errorf("Machine %q: Unable to retrieve object from store: %v", key, err)
+		return err
+	}
+
+	klog.V(2).Infof("reconcileClusterMachineTermination: Start for %q with phase:%q, description:%q",
+		machine.Name, machine.Status.CurrentStatus.Phase, machine.Status.LastOperation.Description)
+	defer klog.V(2).Infof("reconcileClusterMachineTermination: Stop for %q", machine.Name)
+
+	machineClass, secretData, retry, err := c.ValidateMachineClass(ctx, &machine.Spec.Class)
+	if err != nil {
+		klog.Errorf("cannot reconcile machine %q: %s", machine.Name, err)
+		c.enqueueMachineTerminationAfter(machine, time.Duration(retry), err.Error())
+		return err
+	}
+
+	// Process a delete event
+	retryPeriod, err := c.triggerDeletionFlow(
+		ctx,
+		&driver.DeleteMachineRequest{
+			Machine:      machine,
+			MachineClass: machineClass,
+			Secret:       &corev1.Secret{Data: secretData},
+		},
+	)
+
+	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
+	}
+}
+
 /*
 SECTION
 Machine controller - nodeToMachine
@@ -465,30 +561,6 @@ func (c *controller) triggerCreationFlow(ctx context.Context, createMachineReque
 				nodeName = machine.Labels[v1alpha1.NodeLabelKey]
 			}
 
-		case codes.Unknown, codes.DeadlineExceeded, codes.Aborted, codes.Unavailable:
-			// GetMachineStatus() returned with one of the above error codes.
-			// Retry operation.
-			updateRetryPeriod, updateErr := c.machineStatusUpdate(
-				ctx,
-				machine,
-				v1alpha1.LastOperation{
-					Description:    "Cloud provider message - " + err.Error(),
-					State:          v1alpha1.MachineStateFailed,
-					Type:           v1alpha1.MachineOperationCreate,
-					LastUpdateTime: metav1.Now(),
-				},
-				v1alpha1.CurrentStatus{
-					Phase:          c.getCreateFailurePhase(machine),
-					LastUpdateTime: metav1.Now(),
-				},
-				machine.Status.LastKnownState,
-			)
-			if updateErr != nil {
-				return updateRetryPeriod, updateErr
-			}
-
-			return machineutils.ShortRetry, err
-
 		case codes.Uninitialized:
 			uninitializedMachine = true
 			klog.Infof("VM instance associated with machine %s was created but not initialized.", machine.Name)
@@ -498,26 +570,7 @@ func (c *controller) triggerCreationFlow(ctx context.Context, createMachineReque
 			providerID = getMachineStatusResponse.ProviderID
 
 		default:
-			updateRetryPeriod, updateErr := c.machineStatusUpdate(
-				ctx,
-				machine,
-				v1alpha1.LastOperation{
-					Description:    "Cloud provider message - " + err.Error(),
-					State:          v1alpha1.MachineStateFailed,
-					Type:           v1alpha1.MachineOperationCreate,
-					LastUpdateTime: metav1.Now(),
-				},
-				v1alpha1.CurrentStatus{
-					Phase:          c.getCreateFailurePhase(machine),
-					LastUpdateTime: metav1.Now(),
-				},
-				machine.Status.LastKnownState,
-			)
-			if updateErr != nil {
-				return updateRetryPeriod, updateErr
-			}
-
-			return machineutils.MediumRetry, err
+			return c.machineCreateErrorHandler(ctx, machine, nil, err)
 		}
 	} else {
 		if machine.Labels[v1alpha1.NodeLabelKey] == "" || machine.Spec.ProviderID == "" {
diff --git a/pkg/util/provider/machinecontroller/machine_util.go b/pkg/util/provider/machinecontroller/machine_util.go
index a0c10645c..ffd3ab411 100644
--- a/pkg/util/provider/machinecontroller/machine_util.go
+++ b/pkg/util/provider/machinecontroller/machine_util.go
@@ -498,7 +498,8 @@ func SyncMachineTaints(
 	return toBeUpdated
 }
 
-// machineCreateErrorHandler TODO
+// machineCreateErrorHandler updates the machine status based on
+// CreateMachineResponse and the error during the machine creation
 func (c *controller) machineCreateErrorHandler(ctx context.Context, machine *v1alpha1.Machine, createMachineResponse *driver.CreateMachineResponse, err error) (machineutils.RetryPeriod, error) {
 	var (
 		retryRequired  = machineutils.MediumRetry
@@ -509,6 +510,7 @@ func (c *controller) machineCreateErrorHandler(ctx context.Context, machine *v1a
 		switch machineErr.Code() {
 		case codes.Unknown, codes.DeadlineExceeded, codes.Aborted, codes.Unavailable:
 			retryRequired = machineutils.ShortRetry
+			lastKnownState = machine.Status.LastKnownState
 		}
 	}
 
diff --git a/pkg/util/provider/machineutils/utils.go b/pkg/util/provider/machineutils/utils.go
index af1458bff..7d86d4176 100644
--- a/pkg/util/provider/machineutils/utils.go
+++ b/pkg/util/provider/machineutils/utils.go
@@ -50,9 +50,9 @@ const (
 	// NotManagedByMCM annotation helps in identifying the nodes which are not handled by MCM
 	NotManagedByMCM = "node.machine.sapcloud.io/not-managed-by-mcm"
 
-	// TriggerDeletionByMCM annotation on the node would trigger the deletion of the corresponding machine object in the control cluster
+	// TriggerDeletionByMCM annotation on the node or machine would trigger the deletion of the corresponding node and machine object in the control cluster
 	// This annotation can also be set on the MachineDeployment and contains the machine names for which deletion should be triggered.
-	// This feature is leveraged by the CA-MCM cloud provider.
+	// The latter feature is leveraged by the CA-MCM cloud provider.
 	TriggerDeletionByMCM = "node.machine.sapcloud.io/trigger-deletion-by-mcm"
 
 	// NodeUnhealthy is a node termination reason for failed machines
@@ -101,3 +101,18 @@ func IsMachineFailedOrTerminating(machine *v1alpha1.Machine) bool {
 	}
 	return false
 }
+
+// IsMachineActive checks if machine was active
+func IsMachineActive(p *v1alpha1.Machine) bool {
+	return p.Status.CurrentStatus.Phase != v1alpha1.MachineFailed && p.Status.CurrentStatus.Phase != v1alpha1.MachineTerminating
+}
+
+// IsMachineFailed checks if machine has failed
+func IsMachineFailed(p *v1alpha1.Machine) bool {
+	return p.Status.CurrentStatus.Phase == v1alpha1.MachineFailed
+}
+
+// IsMachineTriggeredForDeletion checks if machine was triggered for deletion
+func IsMachineTriggeredForDeletion(m *v1alpha1.Machine) bool {
+	return m.Annotations[MachinePriority] == "1" || m.Annotations[TriggerDeletionByMCM] == "true"
+}



Test patch:
diff --git a/pkg/controller/deployment_test.go b/pkg/controller/deployment_test.go
index ecf504a9b..d378c8fdc 100644
--- a/pkg/controller/deployment_test.go
+++ b/pkg/controller/deployment_test.go
@@ -7,6 +7,9 @@ package controller
 import (
 	"context"
 	"errors"
+	"fmt"
+	"github.com/gardener/machine-controller-manager/pkg/util/annotations"
+	"github.com/gardener/machine-controller-manager/pkg/util/provider/machineutils"
 	"time"
 
 	machinev1 "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1"
@@ -1400,8 +1403,9 @@ var _ = Describe("machineDeployment", func() {
 					Labels: map[string]string{
 						"test-label": "test-label",
 					},
-					UID:        "1234567",
-					Generation: 5,
+					Annotations: make(map[string]string),
+					UID:         "1234567",
+					Generation:  5,
 				},
 				TypeMeta: metav1.TypeMeta{
 					Kind:       "MachineDeployment",
@@ -1506,7 +1510,8 @@ var _ = Describe("machineDeployment", func() {
 						"test-label":           "test-label",
 						machinev1.NodeLabelKey: "Node1-test",
 					},
-					UID: "1234567",
+					Annotations: map[string]string{},
+					UID:         "1234567",
 					OwnerReferences: []metav1.OwnerReference{
 						{
 							Kind:       "MachineSet",
@@ -1552,7 +1557,7 @@ var _ = Describe("machineDeployment", func() {
 
 		DescribeTable("This should",
 			func(preset func(testMachineDeployment *machinev1.MachineDeployment, testMachineSet *machinev1.MachineSet),
-				postCheck func(testMachineDeployment *machinev1.MachineDeployment, testMachineSet []machinev1.MachineSet, testNode *corev1.Node) error) {
+				postCheck func(testMachineDeployment *machinev1.MachineDeployment, testMachineSet []machinev1.MachineSet, testMachines []machinev1.Machine, testNode *corev1.Node) error) {
 
 				stop := make(chan struct{})
 				preset(testMachineDeployment, testMachineSet)
@@ -1575,13 +1580,15 @@ var _ = Describe("machineDeployment", func() {
 				waitForCacheSync(stop, c)
 				actualMachineDeployment, _ := c.controlMachineClient.MachineDeployments(testNamespace).Get(context.Background(), testMachineDeployment.Name, metav1.GetOptions{})
 				actualMachineSets, _ := c.controlMachineClient.MachineSets(testNamespace).List(context.Background(), metav1.ListOptions{})
+				waitForCacheSync(stop, c)
+				actualMachines, _ := c.controlMachineClient.Machines(testNamespace).List(context.Background(), metav1.ListOptions{})
 				testNode, _ := c.targetCoreClient.CoreV1().Nodes().Get(context.Background(), testNode.Name, metav1.GetOptions{})
 
-				Expect(postCheck(actualMachineDeployment, actualMachineSets.Items, testNode)).To(BeNil())
+				Expect(postCheck(actualMachineDeployment, actualMachineSets.Items, actualMachines.Items, testNode)).To(BeNil())
 			},
 			Entry("reconcile the machineDeployment and return nil",
 				func(_ *machinev1.MachineDeployment, _ *machinev1.MachineSet) {},
-				func(_ *machinev1.MachineDeployment, _ []machinev1.MachineSet, _ *corev1.Node) error {
+				func(_ *machinev1.MachineDeployment, _ []machinev1.MachineSet, _ []machinev1.Machine, _ *corev1.Node) error {
 					return nil
 				},
 			),
@@ -1592,7 +1599,7 @@ var _ = Describe("machineDeployment", func() {
 					testMachineSet.Spec = machinev1.MachineSetSpec{}
 					testMachineSet.Status = machinev1.MachineSetStatus{}
 				},
-				func(_ *machinev1.MachineDeployment, testMachineSets []machinev1.MachineSet, _ *corev1.Node) error {
+				func(_ *machinev1.MachineDeployment, testMachineSets []machinev1.MachineSet, _ []machinev1.Machine, _ *corev1.Node) error {
 					if len(testMachineSets) != 1 {
 						return errors.New("it should have created one machine set")
 					}
@@ -1603,10 +1610,11 @@ var _ = Describe("machineDeployment", func() {
 				func(testMachineDeployment *machinev1.MachineDeployment, _ *machinev1.MachineSet) {
 					testMachineDeployment.Spec.Selector = &metav1.LabelSelector{}
 				},
-				func(_ *machinev1.MachineDeployment, testMachineSets []machinev1.MachineSet, _ *corev1.Node) error {
+				func(_ *machinev1.MachineDeployment, testMachineSets []machinev1.MachineSet, _ []machinev1.Machine, _ *corev1.Node) error {
 					if len(testMachineSets) > 1 {
 						return errors.New("it should not have created one machine set")
 					}
+
 					return nil
 				},
 			),
@@ -1614,7 +1622,7 @@ var _ = Describe("machineDeployment", func() {
 				func(testMachineDeployment *machinev1.MachineDeployment, _ *machinev1.MachineSet) {
 					testMachineDeployment.DeletionTimestamp = &metav1.Time{Time: time.Now()}
 				},
-				func(testMachineDeployment *machinev1.MachineDeployment, _ []machinev1.MachineSet, _ *corev1.Node) error {
+				func(testMachineDeployment *machinev1.MachineDeployment, _ []machinev1.MachineSet, _ []machinev1.Machine, _ *corev1.Node) error {
 					if len(testMachineDeployment.Finalizers) > 0 {
 						return errors.New("it should have removed the finalizers")
 					}
@@ -1631,7 +1639,7 @@ var _ = Describe("machineDeployment", func() {
 					testMachineSet.Spec = machinev1.MachineSetSpec{}
 					testMachineSet.Status = machinev1.MachineSetStatus{}
 				},
-				func(_ *machinev1.MachineDeployment, testMachineSets []machinev1.MachineSet, _ *corev1.Node) error {
+				func(_ *machinev1.MachineDeployment, testMachineSets []machinev1.MachineSet, _ []machinev1.Machine, _ *corev1.Node) error {
 					if len(testMachineSets) != 0 {
 						return errors.New("it shouldn't have created machine set")
 					}
@@ -1648,7 +1656,7 @@ var _ = Describe("machineDeployment", func() {
 					testMachineSet.Spec = machinev1.MachineSetSpec{}
 					testMachineSet.Status = machinev1.MachineSetStatus{}
 				},
-				func(_ *machinev1.MachineDeployment, testMachineSets []machinev1.MachineSet, _ *corev1.Node) error {
+				func(_ *machinev1.MachineDeployment, testMachineSets []machinev1.MachineSet, _ []machinev1.Machine, _ *corev1.Node) error {
 					if len(testMachineSets) < 1 {
 						return errors.New("it should have created one machine set")
 					}
@@ -1662,7 +1670,7 @@ var _ = Describe("machineDeployment", func() {
 					}
 					testMachineDeployment.Spec.Template.Spec.Class.Name = "MachineClass-test-new"
 				},
-				func(_ *machinev1.MachineDeployment, testMachineSets []machinev1.MachineSet, _ *corev1.Node) error {
+				func(_ *machinev1.MachineDeployment, testMachineSets []machinev1.MachineSet, _ []machinev1.Machine, _ *corev1.Node) error {
 					// Old machine set should exist and should be scaled-down to zero.
 					if len(testMachineSets) == 0 || testMachineSets[0].Spec.Replicas != 0 {
 						return errors.New("it should have scaled-down old machineSet to zero")
@@ -1691,7 +1699,7 @@ var _ = Describe("machineDeployment", func() {
 					}
 					testMachine = &machinev1.Machine{}
 				},
-				func(testMachineDeployment *machinev1.MachineDeployment, testMachineSets []machinev1.MachineSet, _ *corev1.Node) error {
+				func(testMachineDeployment *machinev1.MachineDeployment, testMachineSets []machinev1.MachineSet, _ []machinev1.Machine, _ *corev1.Node) error {
 					if len(testMachineSets) != 2 || testMachineSets[0].Spec.Replicas != testMachineDeployment.Spec.Replicas {
 						return errors.New("it should have fully scaled-up the new machineSet")
 					}
@@ -1704,7 +1712,7 @@ var _ = Describe("machineDeployment", func() {
 					// This should trigger rolling-update.
 					testMachineDeployment.Spec.Template.Spec.Class.Name = "MachineClass-test-new"
 				},
-				func(_ *machinev1.MachineDeployment, testMachineSets []machinev1.MachineSet, _ *corev1.Node) error {
+				func(_ *machinev1.MachineDeployment, testMachineSets []machinev1.MachineSet, _ []machinev1.Machine, _ *corev1.Node) error {
 					if len(testMachineSets) != 2 {
 						return errors.New("it should have created a new machine set")
 					}
@@ -1716,7 +1724,7 @@ var _ = Describe("machineDeployment", func() {
 					// This should trigger rolling-update.
 					testMachineDeployment.Spec.Template.Spec.Class.Name = "MachineClass-test-new"
 				},
-				func(testMachineDeployment *machinev1.MachineDeployment, testMachineSets []machinev1.MachineSet, _ *corev1.Node) error {
+				func(testMachineDeployment *machinev1.MachineDeployment, testMachineSets []machinev1.MachineSet, _ []machinev1.Machine, _ *corev1.Node) error {
 					/*TODO: when we create a new RS then we assign it the replica count and
 					then we again see if the replica count can be increased in the same reconciliation loop
 					So in our case we first assign it replica count of 1(note a new machine is not created)
@@ -1748,7 +1756,7 @@ var _ = Describe("machineDeployment", func() {
 					}
 
 				},
-				func(testMachineDeployment *machinev1.MachineDeployment, _ []machinev1.MachineSet, _ *corev1.Node) error {
+				func(testMachineDeployment *machinev1.MachineDeployment, _ []machinev1.MachineSet, _ []machinev1.Machine, _ *corev1.Node) error {
 					// RollbackTo should be removed after rollback.
 					if testMachineDeployment.Spec.RollbackTo != nil {
 						return errors.New("RollbackTo field should have been removed from machine-deployment")
@@ -1768,7 +1776,7 @@ var _ = Describe("machineDeployment", func() {
 					testMachineDeployment.Spec.Template.Spec.Class.Name = "MachineClass-test-new"
 					testMachineDeployment.Spec.Paused = true
 				},
-				func(_ *machinev1.MachineDeployment, testMachineSets []machinev1.MachineSet, _ *corev1.Node) error {
+				func(_ *machinev1.MachineDeployment, testMachineSets []machinev1.MachineSet, _ []machinev1.Machine, _ *corev1.Node) error {
 
 					if len(testMachineSets) != 1 {
 						return errors.New("there should be only one old machine-set")
@@ -1781,6 +1789,17 @@ var _ = Describe("machineDeployment", func() {
 					return nil
 				},
 			),
+			Entry("should set MachinePriority=1 for the machines named in TriggerDeletionByMCM annotation in the MachineDeployment",
+				func(testMachineDeployment *machinev1.MachineDeployment, _ *machinev1.MachineSet) {
+					testMachineDeployment.Annotations[machineutils.TriggerDeletionByMCM] = annotations.CreateMachinesTriggeredForDeletionAnnotValue([]string{testMachine.Name})
+				},
+				func(_ *machinev1.MachineDeployment, _ []machinev1.MachineSet, machines []machinev1.Machine, _ *corev1.Node) error {
+					if machines[0].Annotations[machineutils.MachinePriority] != "1" {
+						return fmt.Errorf("testMachine should have its %q annotation set to 1", machineutils.MachinePriority)
+					}
+					return nil
+				},
+			),
 		)
 	})
 
diff --git a/pkg/controller/machineset_test.go b/pkg/controller/machineset_test.go
index d3a85e178..a8d9a2ff9 100644
--- a/pkg/controller/machineset_test.go
+++ b/pkg/controller/machineset_test.go
@@ -7,6 +7,7 @@ package controller
 import (
 	"context"
 	"errors"
+	"github.com/gardener/machine-controller-manager/pkg/util/provider/machineutils"
 	"sync"
 	"time"
 
@@ -608,6 +609,7 @@ var _ = Describe("machineset", func() {
 					Labels: map[string]string{
 						"test-label": "test-label",
 					},
+					Annotations: map[string]string{},
 				},
 				TypeMeta: metav1.TypeMeta{
 					Kind:       "Machine",
@@ -639,6 +641,46 @@ var _ = Describe("machineset", func() {
 					},
 				},
 			}
+
+			testActiveMachine3 = &machinev1.Machine{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "machine-3",
+					Namespace: testNamespace,
+					UID:       "12345610",
+					Labels: map[string]string{
+						"test-label": "test-label",
+					},
+				},
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "Machine",
+					APIVersion: "machine.sapcloud.io/v1alpha1",
+				},
+				Status: machinev1.MachineStatus{
+					CurrentStatus: machinev1.CurrentStatus{
+						Phase: MachineRunning,
+					},
+				},
+			}
+
+			testActiveMachine4 = &machinev1.Machine{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "machine-4",
+					Namespace: testNamespace,
+					UID:       "12345611",
+					Labels: map[string]string{
+						"test-label": "test-label",
+					},
+				},
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "Machine",
+					APIVersion: "machine.sapcloud.io/v1alpha1",
+				},
+				Status: machinev1.MachineStatus{
+					CurrentStatus: machinev1.CurrentStatus{
+						Phase: MachineFailed,
+					},
+				},
+			}
 		})
 
 		// Testcase: ActiveMachines < DesiredMachines
@@ -716,26 +758,6 @@ var _ = Describe("machineset", func() {
 			stop := make(chan struct{})
 			defer close(stop)
 
-			testActiveMachine3 = &machinev1.Machine{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "machine-3",
-					Namespace: testNamespace,
-					UID:       "12345610",
-					Labels: map[string]string{
-						"test-label": "test-label",
-					},
-				},
-				TypeMeta: metav1.TypeMeta{
-					Kind:       "Machine",
-					APIVersion: "machine.sapcloud.io/v1alpha1",
-				},
-				Status: machinev1.MachineStatus{
-					CurrentStatus: machinev1.CurrentStatus{
-						Phase: MachineRunning,
-					},
-				},
-			}
-
 			objects := []runtime.Object{}
 			objects = append(objects, testMachineSet, testActiveMachine1, testActiveMachine2, testActiveMachine3)
 			c, trackers := createController(stop, testNamespace, objects, nil, nil)
@@ -779,26 +801,6 @@ var _ = Describe("machineset", func() {
 				},
 			}
 
-			testActiveMachine4 = &machinev1.Machine{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "machine-4",
-					Namespace: testNamespace,
-					UID:       "12345611",
-					Labels: map[string]string{
-						"test-label": "test-label",
-					},
-				},
-				TypeMeta: metav1.TypeMeta{
-					Kind:       "Machine",
-					APIVersion: "machine.sapcloud.io/v1alpha1",
-				},
-				Status: machinev1.MachineStatus{
-					CurrentStatus: machinev1.CurrentStatus{
-						Phase: MachineFailed,
-					},
-				},
-			}
-
 			objects := []runtime.Object{}
 			objects = append(objects, testMachineSet, testActiveMachine1, testActiveMachine2, testActiveMachine3, testActiveMachine4)
 			c, trackers := createController(stop, testNamespace, objects, nil, nil)
@@ -822,46 +824,6 @@ var _ = Describe("machineset", func() {
 			stop := make(chan struct{})
 			defer close(stop)
 
-			testActiveMachine3 = &machinev1.Machine{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "machine-3",
-					Namespace: testNamespace,
-					UID:       "12345610",
-					Labels: map[string]string{
-						"test-label": "test-label",
-					},
-				},
-				TypeMeta: metav1.TypeMeta{
-					Kind:       "Machine",
-					APIVersion: "machine.sapcloud.io/v1alpha1",
-				},
-				Status: machinev1.MachineStatus{
-					CurrentStatus: machinev1.CurrentStatus{
-						Phase: MachineRunning,
-					},
-				},
-			}
-
-			testActiveMachine4 = &machinev1.Machine{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "machine-4",
-					Namespace: testNamespace,
-					UID:       "12345611",
-					Labels: map[string]string{
-						"test-label": "test-label",
-					},
-				},
-				TypeMeta: metav1.TypeMeta{
-					Kind:       "Machine",
-					APIVersion: "machine.sapcloud.io/v1alpha1",
-				},
-				Status: machinev1.MachineStatus{
-					CurrentStatus: machinev1.CurrentStatus{
-						Phase: MachineRunning,
-					},
-				},
-			}
-
 			objects := []runtime.Object{}
 			objects = append(objects, testMachineSet, testActiveMachine1, testActiveMachine2, testActiveMachine3, testActiveMachine4)
 			c, trackers := createController(stop, testNamespace, objects, nil, nil)
@@ -879,6 +841,38 @@ var _ = Describe("machineset", func() {
 			Expect(Err).Should(BeNil())
 		})
 
+		It("should delete MachinePriority=1 machines and spawn replacement machine", func() {
+			stop := make(chan struct{})
+			defer close(stop)
+			objects := []runtime.Object{}
+
+			staleMachine := testActiveMachine1.DeepCopy()
+			staleMachine.Annotations[machineutils.MachinePriority] = "1"
+
+			objects = append(objects, testMachineSet, staleMachine, testActiveMachine2, testActiveMachine3)
+			c, trackers := createController(stop, testNamespace, objects, nil, nil)
+			defer trackers.Stop()
+			waitForCacheSync(stop, c)
+
+			machines, _ := c.controlMachineClient.Machines(testNamespace).List(context.TODO(), metav1.ListOptions{})
+			Expect(len(machines.Items)).To(Equal(int(testMachineSet.Spec.Replicas)))
+
+			beforeMachines := []*machinev1.Machine{staleMachine, testActiveMachine2, testActiveMachine3}
+			err := c.manageReplicas(context.TODO(), beforeMachines, testMachineSet)
+			Expect(err).Should(BeNil())
+			waitForCacheSync(stop, c)
+
+			_, err = c.controlMachineClient.Machines(testNamespace).Get(context.Background(), staleMachine.Name, metav1.GetOptions{})
+			Expect(err).ShouldNot(BeNil())
+			Expect(err).To(Satisfy(func(e error) bool {
+				return k8sError.IsNotFound(e)
+			}))
+			afterMachines, err := c.controlMachineClient.Machines(testNamespace).List(context.TODO(), metav1.ListOptions{})
+			// replica count is still maintained.
+			Expect(len(afterMachines.Items)).To(Equal(int(testMachineSet.Spec.Replicas)))
+			Expect(err).Should(BeNil())
+
+		})
 	})
 
 	// TODO: This method has dependency on generic-machineclass. Implement later.
diff --git a/pkg/test/integration/common/framework.go b/pkg/test/integration/common/framework.go
index f71d0a615..ae6bcb6d3 100644
--- a/pkg/test/integration/common/framework.go
+++ b/pkg/test/integration/common/framework.go
@@ -5,26 +5,27 @@
 package common
 
 import (
+	"bufio"
+	"bytes"
 	"context"
 	"encoding/json"
 	"fmt"
-	"github.com/gardener/machine-controller-manager/pkg/controller"
-	"io"
 	"log"
 	"os"
 	"os/exec"
+	"path"
 	"path/filepath"
-	"regexp"
 	"strconv"
 	"strings"
 	"time"
 
+	"github.com/gardener/machine-controller-manager/pkg/controller"
+
 	"github.com/onsi/ginkgo/v2"
 
 	"github.com/onsi/gomega"
 	"github.com/onsi/gomega/gexec"
 	appsV1 "k8s.io/api/apps/v1"
-	coreV1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/apimachinery/pkg/watch"
@@ -37,6 +38,8 @@ import (
 
 const (
 	dwdIgnoreScalingAnnotation = "dependency-watchdog.gardener.cloud/ignore-scaling"
+	testMachineDeploymentName  = "test-machine-deployment"
+	testMachineName            = "test-machine"
 )
 
 var (
@@ -98,6 +101,12 @@ var (
 
 	//values for gardener-node-agent-secret-name
 	gnaSecretNameLabelValue = os.Getenv("GNA_SECRET_NAME")
+
+	// Specifies whether the CRDs should be preserved during cleanup at the end
+	preserveCRDDuringCleanup = os.Getenv("PRESERVE_CRD_AT_END")
+
+	// Are the tests running for the virtual provider
+	isVirtualProvider = os.Getenv("IS_VIRTUAL_PROVIDER")
 )
 
 // ProviderSpecPatch struct holds tags for provider, which we want to patch the  machineclass with
@@ -227,226 +236,6 @@ func (c *IntegrationTestFramework) initalizeClusters() error {
 	return nil
 }
 
-func (c *IntegrationTestFramework) prepareMcmDeployment(
-
-	mcContainerImage string,
-	mcmContainerImage string,
-	byCreating bool) error {
-
-	ctx := context.Background()
-
-	if len(machineControllerManagerDeploymentName) == 0 {
-		machineControllerManagerDeploymentName = "machine-controller-manager"
-	}
-
-	if byCreating {
-		// Create clusterroles and clusterrolebindings for control and target cluster
-		// Create secret containing target kubeconfig file
-		// Create machine-deployment using the yaml file
-		controlClusterRegexp, _ := regexp.Compile("control-cluster-role")
-		targetClusterRegexp, _ := regexp.Compile("target-cluster-role")
-		log.Printf("Creating required roles and rolebinginds")
-
-		err := filepath.Walk(
-			filepath.Join(
-				mcmRepoPath,
-				"kubernetes/deployment/out-of-tree/",
-			),
-			func(
-				path string,
-				info os.FileInfo,
-				err error,
-			) error {
-
-				if err != nil {
-					return err
-				}
-
-				if !info.IsDir() {
-					if controlClusterRegexp.MatchString(info.Name()) {
-						err = c.
-							ControlCluster.
-							ApplyFiles(
-								path,
-								controlClusterNamespace,
-							)
-					} else if targetClusterRegexp.MatchString(info.Name()) {
-						err = c.
-							TargetCluster.
-							ApplyFiles(
-								path,
-								"default",
-							)
-					}
-				}
-				return err
-			})
-
-		if err != nil {
-			return err
-		}
-
-		configFile, _ := os.ReadFile(c.TargetCluster.KubeConfigFilePath)
-		if _, err := c.ControlCluster.Clientset.
-			CoreV1().
-			Secrets(controlClusterNamespace).
-			Create(ctx,
-				&coreV1.Secret{
-					ObjectMeta: metav1.ObjectMeta{
-						Name: "machine-controller-manager",
-					},
-					Data: map[string][]byte{
-						"kubeconfig": configFile,
-					},
-					Type: coreV1.SecretTypeOpaque,
-				},
-				metav1.CreateOptions{},
-			); err != nil {
-			return err
-		}
-
-		if err := c.ControlCluster.
-			ApplyFiles(
-				"../../../kubernetes/deployment.yaml",
-				controlClusterNamespace,
-			); err != nil {
-			return err
-		}
-	}
-
-	// mcmDeploymentOrigObj holds a copy of original mcm deployment
-	result, getErr := c.ControlCluster.Clientset.
-		AppsV1().
-		Deployments(controlClusterNamespace).
-		Get(ctx, machineControllerManagerDeploymentName, metav1.GetOptions{})
-
-	if getErr != nil {
-		log.Printf("failed to get latest version of Deployment: %v", getErr)
-		return getErr
-	}
-
-	mcmDeploymentOrigObj = result
-
-	// update containers spec
-	providerSpecificRegexp, _ := regexp.Compile(mcContainerPrefix)
-
-	containers := mcmDeploymentOrigObj.Spec.Template.Spec.Containers
-
-	for i := range containers {
-		if providerSpecificRegexp.MatchString(containers[i].Image) {
-			// set container image to mcContainerImageTag as the name of the container contains provider
-			if len(mcContainerImage) != 0 {
-				containers[i].Image = mcContainerImage
-				var isOptionAvailable bool
-				for option := range containers[i].Command {
-					if strings.Contains(containers[i].Command[option], "machine-drain-timeout=") {
-						isOptionAvailable = true
-						containers[i].Command[option] = "--machine-drain-timeout=5m"
-					}
-				}
-				if !isOptionAvailable {
-					containers[i].Command = append(containers[i].Command, "--machine-drain-timeout=5m")
-				}
-			}
-		} else {
-			// set container image to mcmContainerImageTag as the name of container contains provider
-			if len(mcmContainerImage) != 0 {
-				containers[i].Image = mcmContainerImage
-			}
-
-			// set machine-safety-overshooting-period to 300ms for freeze check to succeed
-			var isOptionAvailable bool
-			for option := range containers[i].Command {
-				if strings.Contains(containers[i].Command[option], "machine-safety-overshooting-period=") {
-					isOptionAvailable = true
-					containers[i].Command[option] = "--machine-safety-overshooting-period=300ms"
-				}
-			}
-			if !isOptionAvailable {
-				containers[i].Command = append(containers[i].Command, "--machine-safety-overshooting-period=300ms")
-			}
-		}
-	}
-
-	// apply updated containers spec to mcmDeploymentObj in kubernetes cluster
-	retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error {
-		// Retrieve the latest version of Deployment before attempting to update
-		// RetryOnConflict uses exponential backoff to avoid exhausting the apiserver
-
-		mcmDeployment, getErr := c.ControlCluster.Clientset.
-			AppsV1().
-			Deployments(controlClusterNamespace).
-			Get(ctx,
-				machineControllerManagerDeploymentName,
-				metav1.GetOptions{},
-			)
-
-		if getErr != nil {
-			log.Printf("failed to get latest version of Deployment: %v", getErr)
-			return getErr
-		}
-
-		mcmDeployment.Spec.Template.Spec.Containers = containers
-		_, updateErr := c.ControlCluster.Clientset.
-			AppsV1().
-			Deployments(controlClusterNamespace).
-			Update(ctx, mcmDeployment, metav1.UpdateOptions{})
-		return updateErr
-	})
-
-	ginkgo.By("Checking controllers are ready in kubernetes cluster")
-	gomega.Eventually(
-		func() error {
-			deployment, err := c.ControlCluster.Clientset.
-				AppsV1().
-				Deployments(controlClusterNamespace).
-				Get(ctx,
-					machineControllerManagerDeploymentName,
-					metav1.GetOptions{},
-				)
-			if err != nil {
-				return err
-			}
-			if deployment.Status.ReadyReplicas == 1 {
-				pods, err := c.ControlCluster.Clientset.
-					CoreV1().
-					Pods(controlClusterNamespace).
-					List(
-						ctx,
-						metav1.ListOptions{
-							LabelSelector: "role=machine-controller-manager",
-						},
-					)
-				if err != nil {
-					return err
-				}
-				podsCount := len(pods.Items)
-				readyPods := 0
-				for _, pod := range pods.Items {
-					if len(pod.Status.ContainerStatuses) < 2 {
-						return fmt.Errorf("containers(s) not ready")
-					}
-					if !pod.Status.ContainerStatuses[0].Ready {
-						return fmt.Errorf("containers(s) not ready.\n%s", pod.Status.ContainerStatuses[0].State.String())
-					}
-					if !pod.Status.ContainerStatuses[1].Ready {
-						return fmt.Errorf("container(s) not ready.\n%s", pod.Status.ContainerStatuses[1].State.String())
-					}
-					readyPods++
-				}
-				if podsCount == readyPods {
-					return nil
-				}
-			}
-			return fmt.Errorf("deployment replicas are not ready.\n%s", deployment.Status.String())
-		},
-		c.timeout,
-		c.pollingInterval).
-		Should(gomega.BeNil())
-
-	return retryErr
-}
-
 func (c *IntegrationTestFramework) scaleMcmDeployment(replicas int32) error {
 
 	ctx := context.Background()
@@ -601,6 +390,7 @@ func (c *IntegrationTestFramework) setupMachineClass() error {
 							Labels:      machineClasses.Items[0].ObjectMeta.Labels,
 							Annotations: machineClasses.Items[0].ObjectMeta.Annotations,
 						},
+						NodeTemplate:         machineClasses.Items[0].NodeTemplate, // virtual
 						ProviderSpec:         machineClasses.Items[0].ProviderSpec,
 						SecretRef:            machineClasses.Items[0].SecretRef,
 						CredentialsSecretRef: machineClasses.Items[0].CredentialsSecretRef,
@@ -765,31 +555,26 @@ func (c *IntegrationTestFramework) runControllersLocally() {
 func (c *IntegrationTestFramework) SetupBeforeSuite() {
 	ctx := context.Background()
 	log.SetOutput(ginkgo.GinkgoWriter)
-	mcContainerImage := os.Getenv("MC_CONTAINER_IMAGE")
-	mcmContainerImage := os.Getenv("MCM_CONTAINER_IMAGE")
 
 	ginkgo.By("Checking for the clusters if provided are available")
 	gomega.Expect(c.initalizeClusters()).To(gomega.BeNil())
 
+	ginkgo.By("Killing any existing processes")
+	stopMCM(ctx)
 	//setting up MCM either locally or by deploying after checking conditions
-	if isControlSeed == "true" {
-
-		if len(mcContainerImage) != 0 || len(mcmContainerImage) != 0 {
-			ginkgo.By("Updating MCM Deployemnt")
-			gomega.Expect(c.prepareMcmDeployment(mcContainerImage, mcmContainerImage, false)).To(gomega.BeNil())
-		} else {
-			checkMcmRepoAvailable()
 
-			ginkgo.By("Scaledown existing machine controllers")
-			gomega.Expect(c.scaleMcmDeployment(0)).To(gomega.BeNil())
+	checkMcmRepoAvailable()
 
-			c.runControllersLocally()
-		}
-	} else {
+	// When running the IT with virtual provider, there's no need to
+	// scale-down MC processes since none are running in the virtual cluster.
+	// Additionally, currently whenever running IT with the virtual provider,
+	// ControlCluster is assumed to be a seed since that simplifies the setup.
+	if isControlSeed == "true" && isVirtualProvider != "true" {
+		ginkgo.By("Scaledown existing machine controllers")
+		gomega.Expect(c.scaleMcmDeployment(0)).To(gomega.BeNil())
+	} else if isControlSeed != "true" {
 		//TODO : Scaledown the MCM deployment of the actual seed of the target cluster
 
-		checkMcmRepoAvailable()
-
 		//create the custom resources in the control cluster using yaml files
 		//available in kubernetes/crds directory of machine-controller-manager repo
 		//resources to be applied are machineclass, machines, machinesets and machinedeployment
@@ -797,13 +582,14 @@ func (c *IntegrationTestFramework) SetupBeforeSuite() {
 		gomega.Expect(c.ControlCluster.
 			ApplyFiles(
 				filepath.Join(mcmRepoPath, "kubernetes/crds"), controlClusterNamespace)).To(gomega.BeNil())
+	}
 
-		if len(mcContainerImage) != 0 || len(mcmContainerImage) != 0 {
-			ginkgo.By("Creating MCM Deployemnt")
-			gomega.Expect(c.prepareMcmDeployment(mcContainerImage, mcmContainerImage, true)).To(gomega.BeNil())
-		} else {
-			c.runControllersLocally()
-		}
+	c.runControllersLocally()
+
+	ginkgo.By("Cleaning any old resources")
+	if c.ControlCluster.McmClient != nil {
+		timeout := int64(900)
+		c.cleanTestResources(ctx, timeout)
 	}
 
 	ginkgo.By("Setup MachineClass")
@@ -826,30 +612,21 @@ func (c *IntegrationTestFramework) SetupBeforeSuite() {
 			machineClass.SecretRef,
 			machineClass.CredentialsSecretRef,
 		)
-	gomega.Expect(err).
-		NotTo(
-			gomega.HaveOccurred(),
-		)
+	gomega.Expect(err).NotTo(gomega.HaveOccurred())
 
-	ginkgo.By(
-		"Initializing orphan resource tracker",
-	)
+	ginkgo.By("Initializing orphan resource tracker")
 	err = c.resourcesTracker.InitializeResourcesTracker(machineClass, secretData, clusterName)
-
 	gomega.Expect(err).NotTo(gomega.HaveOccurred())
 	log.Println("orphan resource tracker initialized")
-
 }
 
 // BeforeEachCheck checks if all the nodes are ready and the controllers are runnings
 func (c *IntegrationTestFramework) BeforeEachCheck() {
 	ginkgo.BeforeEach(func() {
-		if len(os.Getenv("MC_CONTAINER_IMAGE")) == 0 && len(os.Getenv("MCM_CONTAINER_IMAGE")) == 0 {
-			ginkgo.By("Checking machineController process is running")
-			gomega.Expect(mcsession.ExitCode()).Should(gomega.Equal(-1))
-			ginkgo.By("Checking machineControllerManager process is running")
-			gomega.Expect(mcmsession.ExitCode()).Should(gomega.Equal(-1))
-		}
+		ginkgo.By("Checking machineController process is running")
+		gomega.Expect(mcsession.ExitCode()).Should(gomega.Equal(-1))
+		ginkgo.By("Checking machineControllerManager process is running")
+		gomega.Expect(mcmsession.ExitCode()).Should(gomega.Equal(-1))
 		ginkgo.By("Checking nodes in target cluster are healthy")
 		gomega.Eventually(
 			c.TargetCluster.GetNumberOfReadyNodes,
@@ -870,6 +647,12 @@ func (c *IntegrationTestFramework) ControllerTests() {
 		var initialNodes int16
 		ginkgo.Context("creation", func() {
 			ginkgo.It("should not lead to any errors and add 1 more node in target cluster", func() {
+				// In case of existing deployments creating nodes when starting virtual
+				// provider, the change in node count can be >1, this delay prevents
+				// checking node count immediately to allow for a correct initial count
+				if isVirtualProvider == "true" {
+					time.Sleep(2 * time.Second)
+				}
 				// Probe nodes currently available in target cluster
 				initialNodes = c.TargetCluster.GetNumberOfNodes()
 				ginkgo.By("Checking for errors")
@@ -903,7 +686,7 @@ func (c *IntegrationTestFramework) ControllerTests() {
 							c.ControlCluster.McmClient.
 								MachineV1alpha1().
 								Machines(controlClusterNamespace).
-								Delete(ctx, "test-machine", metav1.DeleteOptions{})).
+								Delete(ctx, testMachineName, metav1.DeleteOptions{})).
 							Should(gomega.BeNil(), "No Errors while deleting machine")
 
 						ginkgo.By("Waiting until test-machine machine object is deleted")
@@ -913,7 +696,7 @@ func (c *IntegrationTestFramework) ControllerTests() {
 							c.pollingInterval).
 							Should(gomega.BeTrue())
 
-						ginkgo.By("Waiting until number of ready nodes is equal to number of initial  nodes")
+						ginkgo.By("Waiting until number of ready nodes is equal to number of initial nodes")
 						gomega.Eventually(
 							c.TargetCluster.GetNumberOfNodes,
 							c.timeout,
@@ -957,6 +740,7 @@ func (c *IntegrationTestFramework) ControllerTests() {
 	// Testcase #02 | machine deployment
 	ginkgo.Describe("machine deployment resource", func() {
 		var initialNodes int16 // initialization should be part of creation test logic
+		initialEventCount := 0
 		ginkgo.Context("creation with replicas=0, scale up with replicas=1", func() {
 			ginkgo.It("should not lead to errors and add 1 more node to target cluster", func() {
 				var machineDeployment *v1alpha1.MachineDeployment
@@ -967,14 +751,14 @@ func (c *IntegrationTestFramework) ControllerTests() {
 				gomega.Expect(c.ControlCluster.CreateMachineDeployment(controlClusterNamespace, gnaSecretNameLabelValue, 0)).To(gomega.BeNil())
 
 				ginkgo.By("Waiting for Machine Set to be created")
-				gomega.Eventually(func() int { return c.getNumberOfMachineSets(ctx, controlClusterNamespace) }, c.timeout, c.pollingInterval).Should(gomega.BeNumerically("==", 1))
+				gomega.Eventually(func() int { return len(c.getTestMachineSets(ctx, controlClusterNamespace)) }, c.timeout, c.pollingInterval).Should(gomega.BeNumerically("==", 1))
 
 				ginkgo.By("Updating machineDeployment replicas to 1")
 				retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error {
 					machineDeployment, _ = c.ControlCluster.McmClient.
 						MachineV1alpha1().
 						MachineDeployments(controlClusterNamespace).
-						Get(ctx, "test-machine-deployment", metav1.GetOptions{})
+						Get(ctx, testMachineDeploymentName, metav1.GetOptions{})
 					machineDeployment.Spec.Replicas = 1
 					_, updateErr := c.ControlCluster.McmClient.
 						MachineV1alpha1().
@@ -991,7 +775,7 @@ func (c *IntegrationTestFramework) ControllerTests() {
 					machineDeployment, err = c.ControlCluster.McmClient.
 						MachineV1alpha1().
 						MachineDeployments(controlClusterNamespace).
-						Get(ctx, "test-machine-deployment", metav1.GetOptions{})
+						Get(ctx, testMachineDeploymentName, metav1.GetOptions{})
 					gomega.Expect(err).NotTo(gomega.HaveOccurred())
 					if len(machineDeployment.Status.Conditions) != 2 {
 						return false
@@ -1021,6 +805,8 @@ func (c *IntegrationTestFramework) ControllerTests() {
 					c.timeout,
 					c.pollingInterval).
 					Should(gomega.BeNumerically("==", initialNodes+1))
+				ginkgo.By("Fetching initial number of machineset freeze events")
+				initialEventCount = c.machineSetFreezeEventCount(ctx, controlClusterNamespace)
 			})
 		})
 		ginkgo.Context("scale-up with replicas=6", func() {
@@ -1029,7 +815,7 @@ func (c *IntegrationTestFramework) ControllerTests() {
 					machineDployment, _ := c.ControlCluster.McmClient.
 						MachineV1alpha1().
 						MachineDeployments(controlClusterNamespace).
-						Get(ctx, "test-machine-deployment", metav1.GetOptions{})
+						Get(ctx, testMachineDeploymentName, metav1.GetOptions{})
 					machineDployment.Spec.Replicas = 6
 					_, updateErr := c.ControlCluster.McmClient.
 						MachineV1alpha1().
@@ -1059,7 +845,7 @@ func (c *IntegrationTestFramework) ControllerTests() {
 					machineDployment, _ := c.ControlCluster.McmClient.
 						MachineV1alpha1().
 						MachineDeployments(controlClusterNamespace).
-						Get(ctx, "test-machine-deployment", metav1.GetOptions{})
+						Get(ctx, testMachineDeploymentName, metav1.GetOptions{})
 					machineDployment.Spec.Replicas = 2
 					_, updateErr := c.ControlCluster.McmClient.
 						MachineV1alpha1().
@@ -1084,68 +870,9 @@ func (c *IntegrationTestFramework) ControllerTests() {
 			})
 			// rapid scaling back to 2, should lead to freezing and unfreezing
 			ginkgo.It("should freeze and unfreeze machineset temporarily", func() {
-				if mcsession == nil {
-					// controllers running in pod
-					// Create log file from container log
-					mcmOutputFile, err := rotateOrAppendLogFile(mcmLogFile, true)
-					gomega.Expect(err).NotTo(gomega.HaveOccurred())
-					mcOutputFile, err := rotateOrAppendLogFile(mcLogFile, true)
-					gomega.Expect(err).NotTo(gomega.HaveOccurred())
-					ginkgo.By("Reading container log is leading to no errors")
-					podList, err := c.ControlCluster.Clientset.
-						CoreV1().
-						Pods(controlClusterNamespace).
-						List(
-							ctx,
-							metav1.ListOptions{
-								LabelSelector: "role=machine-controller-manager",
-							},
-						)
-					gomega.Expect(err).NotTo(gomega.HaveOccurred())
-
-					mcmPod := podList.Items[0]
-					providerSpecificRegexp, _ := regexp.Compile(mcContainerPrefix)
-					containers := mcmPod.Spec.Containers
-
-					for i := range containers {
-						if providerSpecificRegexp.Match([]byte(containers[i].Image)) {
-							readCloser, err := c.ControlCluster.Clientset.CoreV1().
-								Pods(controlClusterNamespace).
-								GetLogs(
-									mcmPod.Name,
-									&coreV1.PodLogOptions{
-										Container: containers[i].Name,
-									},
-								).Stream(ctx)
-							gomega.Expect(err).NotTo(gomega.HaveOccurred())
-							_, err = io.Copy(mcOutputFile, readCloser)
-							gomega.Expect(err).NotTo(gomega.HaveOccurred())
-						} else {
-							readCloser, err := c.ControlCluster.Clientset.CoreV1().
-								Pods(controlClusterNamespace).
-								GetLogs(mcmPod.Name, &coreV1.PodLogOptions{
-									Container: containers[i].Name,
-								}).Stream(ctx)
-							gomega.Expect(err).NotTo(gomega.HaveOccurred())
-							_, err = io.Copy(mcmOutputFile, readCloser)
-							gomega.Expect(err).NotTo(gomega.HaveOccurred())
-						}
-					}
-				}
-
-				ginkgo.By("Searching for Froze in mcm log file")
-				frozeRegexp, _ := regexp.Compile(` Froze MachineSet`)
-				gomega.Eventually(func() bool {
-					data, _ := os.ReadFile(mcmLogFile) // #nosec G304 -- Test only
-					return frozeRegexp.Match(data)
-				}, c.timeout, c.pollingInterval).Should(gomega.BeTrue())
-
-				ginkgo.By("Searching Unfroze in mcm log file")
-				unfrozeRegexp, _ := regexp.Compile(` Unfroze MachineSet`)
-				gomega.Eventually(func() bool {
-					data, _ := os.ReadFile(mcmLogFile) // #nosec G304 -- Test only
-					return unfrozeRegexp.Match(data)
-				}, c.timeout, c.pollingInterval).Should(gomega.BeTrue())
+				gomega.Eventually(func() int {
+					return c.machineSetFreezeEventCount(ctx, controlClusterNamespace)
+				}, c.timeout, c.pollingInterval).Should(gomega.Equal(initialEventCount + 2))
 			})
 		})
 		ginkgo.Context("updation to v2 machine-class and replicas=4", func() {
@@ -1156,7 +883,7 @@ func (c *IntegrationTestFramework) ControllerTests() {
 					machineDployment, _ := c.ControlCluster.McmClient.
 						MachineV1alpha1().
 						MachineDeployments(controlClusterNamespace).
-						Get(ctx, "test-machine-deployment", metav1.GetOptions{})
+						Get(ctx, testMachineDeploymentName, metav1.GetOptions{})
 					machineDployment.Spec.Template.Spec.Class.Name = testMachineClassResources[1]
 					machineDployment.Spec.Replicas = 4
 					_, updateErr := c.ControlCluster.McmClient.
@@ -1172,7 +899,7 @@ func (c *IntegrationTestFramework) ControllerTests() {
 					machineDeployment, err := c.ControlCluster.McmClient.
 						MachineV1alpha1().
 						MachineDeployments(controlClusterNamespace).
-						Get(ctx, "test-machine-deployment", metav1.GetOptions{})
+						Get(ctx, testMachineDeploymentName, metav1.GetOptions{})
 					if err != nil {
 						log.Println("Failed to get machinedeployment object")
 					}
@@ -1183,7 +910,7 @@ func (c *IntegrationTestFramework) ControllerTests() {
 					machineDeployment, err := c.ControlCluster.McmClient.
 						MachineV1alpha1().
 						MachineDeployments(controlClusterNamespace).
-						Get(ctx, "test-machine-deployment", metav1.GetOptions{})
+						Get(ctx, testMachineDeploymentName, metav1.GetOptions{})
 					if err != nil {
 						log.Println("Failed to get machinedeployment object")
 					}
@@ -1209,7 +936,7 @@ func (c *IntegrationTestFramework) ControllerTests() {
 					_, err := c.ControlCluster.McmClient.
 						MachineV1alpha1().
 						MachineDeployments(controlClusterNamespace).
-						Get(ctx, "test-machine-deployment", metav1.GetOptions{})
+						Get(ctx, testMachineDeploymentName, metav1.GetOptions{})
 					if err == nil {
 						ginkgo.By("Checking for errors")
 						gomega.Expect(
@@ -1218,7 +945,7 @@ func (c *IntegrationTestFramework) ControllerTests() {
 								MachineDeployments(controlClusterNamespace).
 								Delete(
 									ctx,
-									"test-machine-deployment",
+									testMachineDeploymentName,
 									metav1.DeleteOptions{},
 								)).
 							Should(gomega.BeNil())
@@ -1263,134 +990,62 @@ func (c *IntegrationTestFramework) Cleanup() {
 
 	ginkgo.By("Running Cleanup")
 	//running locally, means none of the image is specified
-	if len(os.Getenv("MC_CONTAINER_IMAGE")) == 0 && len(os.Getenv("MCM_CONTAINER_IMAGE")) == 0 {
-		for i := 0; i < 5; i++ {
-			if mcsession.ExitCode() != -1 {
-				ginkgo.By("Restarting Machine Controller ")
-				outputFile, err := rotateOrAppendLogFile(mcLogFile, false)
-				gomega.Expect(err).NotTo(gomega.HaveOccurred())
-				_, err = outputFile.WriteString("\n------------RESTARTED MC------------\n")
-				gomega.Expect(err).NotTo(gomega.HaveOccurred())
-				args := strings.Fields(
-					fmt.Sprintf(
-						"make --directory=%s start CONTROL_KUBECONFIG=%s TARGET_KUBECONFIG=%s CONTROL_NAMESPACE=%s LEADER_ELECT=false ",
-						"../../..",
-						c.ControlCluster.KubeConfigFilePath,
-						c.TargetCluster.KubeConfigFilePath,
-						controlClusterNamespace),
-				)
-				mcsession, err = gexec.Start(exec.Command(args[0], args[1:]...), outputFile, outputFile) // #nosec G204 -- Test only
-				gomega.Expect(err).NotTo(gomega.HaveOccurred())
-				break
-			}
-			time.Sleep(2 * time.Second)
+	for range 5 {
+		if mcsession.ExitCode() != -1 {
+			ginkgo.By("Restarting Machine Controller ")
+			outputFile, err := rotateOrAppendLogFile(mcLogFile, false)
+			gomega.Expect(err).NotTo(gomega.HaveOccurred())
+			_, err = outputFile.WriteString("\n------------RESTARTED MC------------\n")
+			gomega.Expect(err).NotTo(gomega.HaveOccurred())
+			args := strings.Fields(
+				fmt.Sprintf(
+					"make --directory=%s start CONTROL_KUBECONFIG=%s TARGET_KUBECONFIG=%s CONTROL_NAMESPACE=%s LEADER_ELECT=false ",
+					"../../..",
+					c.ControlCluster.KubeConfigFilePath,
+					c.TargetCluster.KubeConfigFilePath,
+					controlClusterNamespace),
+			)
+			mcsession, err = gexec.Start(exec.Command(args[0], args[1:]...), outputFile, outputFile) // #nosec G204 -- Test only
+			gomega.Expect(err).NotTo(gomega.HaveOccurred())
+			break
 		}
-		for i := 0; i < 5; i++ {
-			if mcmsession.ExitCode() != -1 {
-				ginkgo.By("Restarting Machine Controller Manager")
-				outputFile, err := rotateOrAppendLogFile(mcmLogFile, false)
-				gomega.Expect(err).NotTo(gomega.HaveOccurred())
-				_, err = outputFile.WriteString("\n------------RESTARTED MCM------------\n")
-				gomega.Expect(err).NotTo(gomega.HaveOccurred())
-				args := strings.Fields(
-					fmt.Sprintf(
-						"make --directory=%s start CONTROL_KUBECONFIG=%s TARGET_KUBECONFIG=%s CONTROL_NAMESPACE=%s LEADER_ELECT=false MACHINE_SAFETY_OVERSHOOTING_PERIOD=300ms",
-						mcmRepoPath,
-						c.ControlCluster.KubeConfigFilePath,
-						c.TargetCluster.KubeConfigFilePath,
-						controlClusterNamespace),
-				)
-				mcmsession, err = gexec.Start(exec.Command(args[0], args[1:]...), outputFile, outputFile) // #nosec G204 -- Test only
-				gomega.Expect(err).NotTo(gomega.HaveOccurred())
-				break
-			}
-			time.Sleep(2 * time.Second)
+		time.Sleep(2 * time.Second)
+	}
+	for range 5 {
+		if mcmsession.ExitCode() != -1 {
+			ginkgo.By("Restarting Machine Controller Manager")
+			outputFile, err := rotateOrAppendLogFile(mcmLogFile, false)
+			gomega.Expect(err).NotTo(gomega.HaveOccurred())
+			_, err = outputFile.WriteString("\n------------RESTARTED MCM------------\n")
+			gomega.Expect(err).NotTo(gomega.HaveOccurred())
+			args := strings.Fields(
+				fmt.Sprintf(
+					"make --directory=%s start CONTROL_KUBECONFIG=%s TARGET_KUBECONFIG=%s CONTROL_NAMESPACE=%s LEADER_ELECT=false MACHINE_SAFETY_OVERSHOOTING_PERIOD=300ms",
+					mcmRepoPath,
+					c.ControlCluster.KubeConfigFilePath,
+					c.TargetCluster.KubeConfigFilePath,
+					controlClusterNamespace),
+			)
+			mcmsession, err = gexec.Start(exec.Command(args[0], args[1:]...), outputFile, outputFile) // #nosec G204 -- Test only
+			gomega.Expect(err).NotTo(gomega.HaveOccurred())
+			break
 		}
+		time.Sleep(2 * time.Second)
 	}
 
-	if c.ControlCluster.McmClient != nil {
+	if preserveCRDDuringCleanup == "true" {
+		log.Printf("Preserve CRD: %s\n", preserveCRDDuringCleanup)
+	} else if c.ControlCluster.McmClient != nil {
 		timeout := int64(900)
-		// Check and delete machinedeployment resource
-		_, err := c.ControlCluster.McmClient.
-			MachineV1alpha1().
-			MachineDeployments(controlClusterNamespace).
-			Get(ctx, "test-machine-deployment", metav1.GetOptions{})
-		if err == nil {
-			log.Println("deleting test-machine-deployment")
-			watchMachinesDepl, _ := c.ControlCluster.McmClient.
-				MachineV1alpha1().
-				MachineDeployments(controlClusterNamespace).
-				Watch(ctx, metav1.ListOptions{TimeoutSeconds: &timeout}) //ResourceVersion: machineDeploymentObj.ResourceVersion
-			for event := range watchMachinesDepl.ResultChan() {
-				gomega.Expect(c.ControlCluster.McmClient.
-					MachineV1alpha1().
-					MachineDeployments(controlClusterNamespace).
-					Delete(ctx, "test-machine-deployment", metav1.DeleteOptions{})).To(gomega.Or(gomega.Succeed(), matchers.BeNotFoundError()))
-				if event.Type == watch.Deleted {
-					watchMachinesDepl.Stop()
-					log.Println("machinedeployment deleted")
-				}
-			}
-		} else {
-			log.Println(err.Error())
-		}
-		// Check and delete machine resource
-		_, err = c.ControlCluster.McmClient.
-			MachineV1alpha1().
-			Machines(controlClusterNamespace).
-			Get(ctx, "test-machine", metav1.GetOptions{})
-		if err == nil {
-			log.Println("deleting test-machine")
-			watchMachines, _ := c.ControlCluster.McmClient.
-				MachineV1alpha1().
-				Machines(controlClusterNamespace).
-				Watch(ctx, metav1.ListOptions{TimeoutSeconds: &timeout}) //ResourceVersion: machineObj.ResourceVersion
-			for event := range watchMachines.ResultChan() {
-				gomega.Expect(c.ControlCluster.McmClient.
-					MachineV1alpha1().
-					Machines(controlClusterNamespace).
-					Delete(ctx, "test-machine", metav1.DeleteOptions{})).To(gomega.Or(gomega.Succeed(), matchers.BeNotFoundError()))
-				if event.Type == watch.Deleted {
-					watchMachines.Stop()
-					log.Println("machine deleted")
-				}
-			}
-		} else {
-			log.Println(err.Error())
-		}
+		c.cleanTestResources(ctx, timeout)
+	}
 
-		for _, machineClassName := range testMachineClassResources {
-			// Check and delete machine class resource
-			_, err = c.ControlCluster.McmClient.
-				MachineV1alpha1().
-				MachineClasses(controlClusterNamespace).
-				Get(ctx, machineClassName, metav1.GetOptions{})
-			if err == nil {
-				log.Printf("deleting %s machineclass", machineClassName)
-				watchMachineClass, _ := c.ControlCluster.McmClient.
-					MachineV1alpha1().
-					MachineClasses(controlClusterNamespace).
-					Watch(ctx, metav1.ListOptions{TimeoutSeconds: &timeout})
-				for event := range watchMachineClass.ResultChan() {
-					gomega.Expect(c.ControlCluster.McmClient.
-						MachineV1alpha1().
-						MachineClasses(controlClusterNamespace).
-						Delete(ctx, machineClassName, metav1.DeleteOptions{})).To(gomega.Or(gomega.Succeed(), matchers.BeNotFoundError()))
-					if event.Type == watch.Deleted {
-						watchMachineClass.Stop()
-						log.Println("machineclass deleted")
-					}
-				}
-			} else {
-				log.Println(err.Error())
-			}
-		}
+	ginkgo.By("Killing any existing processes")
+	stopMCM(ctx)
 
-	}
 	if isControlSeed == "true" {
-		// scale back up the MCM deployment to 1 in the Control Cluster
 		// This is needed when IT suite runs locally against a Control & Target cluster
-
+		ginkgo.By("Scale back the existing machine controllers")
 		if err := c.scaleMcmDeployment(1); err != nil {
 			log.Println(err.Error())
 		}
@@ -1403,71 +1058,227 @@ func (c *IntegrationTestFramework) Cleanup() {
 		); err != nil {
 			log.Printf("Error occured while deleting crds. %s", err.Error())
 		}
+	}
 
-		if len(os.Getenv("MC_CONTAINER_IMAGE")) != 0 || len(os.Getenv("MCM_CONTAINER_IMAGE")) != 0 {
-			log.Println("Deleting Clusterroles")
+}
 
-			if err := c.ControlCluster.RbacClient.ClusterRoles().Delete(
-				ctx,
-				"machine-controller-manager-control",
-				metav1.DeleteOptions{},
-			); err != nil {
-				log.Printf("Error occured while deleting clusterrole. %s", err.Error())
-			}
+func (c *IntegrationTestFramework) cleanTestResources(ctx context.Context, timeout int64) {
+	// Check and delete machinedeployment resource
+	if err := c.cleanMachineDeployment(ctx, testMachineDeploymentName, timeout); err != nil {
+		log.Println(err.Error())
+	}
+	// Check and delete machine resource
+	if err := c.cleanMachine(ctx, testMachineName, timeout); err != nil {
+		log.Println(err.Error())
+	}
 
-			if err := c.ControlCluster.RbacClient.ClusterRoleBindings().Delete(
-				ctx,
-				"machine-controller-manager-control",
-				metav1.DeleteOptions{},
-			); err != nil {
-				log.Printf("Error occured while deleting clusterrolebinding . %s", err.Error())
-			}
+	for _, machineClassName := range testMachineClassResources {
+		// Check and delete machine class resource
+		if err := c.cleanMachineClass(ctx, machineClassName, timeout); err != nil {
+			log.Println(err.Error())
+		}
+	}
+}
 
-			if err := c.TargetCluster.RbacClient.ClusterRoles().Delete(
-				ctx,
-				"machine-controller-manager-target",
-				metav1.DeleteOptions{},
-			); err != nil {
-				log.Printf("Error occured while deleting clusterrole . %s", err.Error())
-			}
+func (c *IntegrationTestFramework) cleanMachineDeployment(ctx context.Context, name string, timeout int64) error {
+	_, err := c.ControlCluster.McmClient.
+		MachineV1alpha1().
+		MachineDeployments(controlClusterNamespace).
+		Get(ctx, name, metav1.GetOptions{})
+	if err != nil {
+		return err
+	}
+	log.Printf("deleting %s\n", name)
+	selector := fmt.Sprintf("metadata.name=%s", name)
+	watchMachinesDepl, _ := c.ControlCluster.McmClient.
+		MachineV1alpha1().
+		MachineDeployments(controlClusterNamespace).
+		Watch(ctx, metav1.ListOptions{
+			TimeoutSeconds: &timeout,
+			FieldSelector:  selector,
+		})
+	for event := range watchMachinesDepl.ResultChan() {
+		gomega.Expect(c.ControlCluster.McmClient.
+			MachineV1alpha1().
+			MachineDeployments(controlClusterNamespace).
+			Delete(ctx, name, metav1.DeleteOptions{})).To(gomega.Or(gomega.Succeed(), matchers.BeNotFoundError()))
+		if event.Type == watch.Deleted {
+			watchMachinesDepl.Stop()
+			log.Println("machinedeployment deleted")
+		}
+	}
+	return nil
+}
 
-			if err := c.TargetCluster.RbacClient.ClusterRoleBindings().Delete(
-				ctx,
-				"machine-controller-manager-target",
-				metav1.DeleteOptions{},
-			); err != nil {
-				log.Printf("Error occured while deleting clusterrolebinding . %s", err.Error())
-			}
+func (c *IntegrationTestFramework) cleanMachine(ctx context.Context, name string, timeout int64) error {
+	_, err := c.ControlCluster.McmClient.
+		MachineV1alpha1().
+		Machines(controlClusterNamespace).
+		Get(ctx, name, metav1.GetOptions{})
+	if err != nil {
+		return err
+	}
+	log.Printf("deleting %s\n", name)
+	selector := fmt.Sprintf("metadata.name=%s", name)
+	watchMachines, _ := c.ControlCluster.McmClient.
+		MachineV1alpha1().
+		Machines(controlClusterNamespace).
+		Watch(ctx, metav1.ListOptions{
+			TimeoutSeconds: &timeout,
+			FieldSelector:  selector,
+		}) //ResourceVersion: machineObj.ResourceVersion
+	for event := range watchMachines.ResultChan() {
+		gomega.Expect(c.ControlCluster.McmClient.
+			MachineV1alpha1().
+			Machines(controlClusterNamespace).
+			Delete(ctx, name, metav1.DeleteOptions{})).To(gomega.Or(gomega.Succeed(), matchers.BeNotFoundError()))
+		if event.Type == watch.Deleted {
+			watchMachines.Stop()
+			log.Println("machine deleted")
+		}
+	}
+	return nil
+}
 
-			log.Println("Deleting MCM deployment")
+func (c *IntegrationTestFramework) cleanMachineClass(ctx context.Context, machineClassName string, timeout int64) error {
+	_, err := c.ControlCluster.McmClient.
+		MachineV1alpha1().
+		MachineClasses(controlClusterNamespace).
+		Get(ctx, machineClassName, metav1.GetOptions{})
+	if err != nil {
+		return err
+	}
 
-			gomega.Expect(c.ControlCluster.Clientset.
-				CoreV1().
-				Secrets(controlClusterNamespace).
-				Delete(ctx,
-					"machine-controller-manager",
-					metav1.DeleteOptions{})).To(gomega.Or(gomega.Succeed(), matchers.BeNotFoundError()))
-			gomega.Expect(c.ControlCluster.Clientset.
-				AppsV1().
-				Deployments(controlClusterNamespace).
-				Delete(ctx,
-					machineControllerManagerDeploymentName,
-					metav1.DeleteOptions{})).To(gomega.Or(gomega.Succeed(), matchers.BeNotFoundError()))
+	log.Printf("deleting %s machineclass", machineClassName)
+	selector := fmt.Sprintf("metadata.name=%s", machineClassName)
+	watchMachineClass, _ := c.ControlCluster.McmClient.
+		MachineV1alpha1().
+		MachineClasses(controlClusterNamespace).
+		Watch(ctx, metav1.ListOptions{
+			TimeoutSeconds: &timeout,
+			FieldSelector:  selector,
+		})
+	for event := range watchMachineClass.ResultChan() {
+		gomega.Expect(c.ControlCluster.McmClient.
+			MachineV1alpha1().
+			MachineClasses(controlClusterNamespace).
+			Delete(ctx, machineClassName, metav1.DeleteOptions{})).To(gomega.Or(gomega.Succeed(), matchers.BeNotFoundError()))
+		if event.Type == watch.Deleted {
+			watchMachineClass.Stop()
+			log.Println("machineclass deleted")
+		}
+	}
+	return nil
+}
+
+func stopMCM(ctx context.Context) {
+	processesToKill := []string{
+		"machine-controller-manager --control-kubeconfig", // virtual
+		"machine-controller --control-kubeconfig",         // virtual
+		"controller_manager --control-kubeconfig",
+		"main --control-kubeconfig",
+		"go run cmd/machine-controller/main.go",
+		"go run cmd/machine-controller-manager/controller_manager.go",
+		"make --directory=../../..",
+	}
+	for _, proc := range processesToKill {
+		pids, err := findAndKillProcess(ctx, proc)
+		if err != nil {
+			log.Println(err.Error())
+		}
+		if len(pids) > 0 {
+			log.Printf("stopMCM killed MCM process(es) with pid(s): %v\n", pids)
 		}
 	}
+}
 
+func findAndKillProcess(ctx context.Context, prefix string) (pids []int, err error) {
+	pids, err = findPidsByPrefix(ctx, prefix)
+	if len(pids) != 0 {
+		var proc *os.Process
+		for _, pid := range pids {
+			proc, err = os.FindProcess(pid)
+			if err != nil {
+				err = fmt.Errorf("failed to find process with PID %d: %v", pid, err)
+				return
+			}
+			err = proc.Kill()
+			if err != nil {
+				err = fmt.Errorf("failed to kill process with PID %d: %v", pid, err)
+				return
+			}
+		}
+	}
+	return
 }
 
-func (c *IntegrationTestFramework) getNumberOfMachineSets(ctx context.Context, namespace string) int {
+func findPidsByPrefix(ctx context.Context, prefix string) (pids []int, err error) {
+	cmd := exec.CommandContext(ctx, "ps", "-e", "-o", "pid,args")
+	psOutput, err := cmd.Output()
+	if err != nil {
+		log.Printf("FindProcess could not run ps command: %v", err)
+		return
+	}
+	scanner := bufio.NewScanner(bytes.NewReader(psOutput))
+	var pid int
+	for scanner.Scan() {
+		line := scanner.Text()
+		fields := strings.Fields(line)
+		if len(fields) < 2 {
+			continue
+		}
+		// Process the PID and command columns
+		pidStr := fields[0]
+		commandPath := fields[1]
+		commandName := path.Base(commandPath)
+		if len(fields) > 2 {
+			commandName = commandName + " " + strings.Join(fields[2:], " ")
+		}
+
+		if strings.HasPrefix(commandName, prefix) {
+			log.Println(commandName)
+			pid, err = strconv.Atoi(pidStr)
+			if err != nil {
+				err = fmt.Errorf("invalid pid: %s", pidStr)
+				return
+			}
+			pids = append(pids, pid)
+		}
+	}
+	return
+}
+
+func (c *IntegrationTestFramework) getTestMachineSets(ctx context.Context, namespace string) []string {
 	machineSets, err := c.ControlCluster.McmClient.MachineV1alpha1().MachineSets(namespace).List(ctx, metav1.ListOptions{})
+	testMachineSets := []string{}
 	gomega.Expect(err).NotTo(gomega.HaveOccurred())
-	count := 0
 	for _, machineSet := range machineSets.Items {
-		if machineSet.OwnerReferences[0].Name == "test-machine-deployment" {
-			count++
+		if machineSet.OwnerReferences[0].Name == testMachineDeploymentName {
+			testMachineSets = append(testMachineSets, machineSet.Name)
+		}
+	}
+	return testMachineSets
+}
+
+func (c *IntegrationTestFramework) machineSetFreezeEventCount(ctx context.Context, namespace string) int {
+	eventCount := 0
+	testMachineSets := c.getTestMachineSets(ctx, namespace)
+	machineSetFreezeReason := fmt.Sprintf("reason=%s", controller.MachineSetFreezeEvent)
+	machineSetUnfreezeReason := fmt.Sprintf("reason=%s", controller.MachineSetUnfreezeEvent)
+	for _, machineSet := range testMachineSets {
+		for _, reason := range []string{machineSetFreezeReason, machineSetUnfreezeReason} {
+			event := fmt.Sprintf("%s,involvedObject.name=%s", reason, machineSet)
+			frozenEvents, err := c.ControlCluster.Clientset.
+				CoreV1().
+				Events(namespace).
+				List(ctx, metav1.ListOptions{
+					FieldSelector: event,
+				})
+			gomega.Expect(err).NotTo(gomega.HaveOccurred())
+			eventCount += len(frozenEvents.Items)
 		}
 	}
-	return count
+	return eventCount
 }
 
 func checkMcmRepoAvailable() {
diff --git a/pkg/util/provider/machinecontroller/controller_suite_test.go b/pkg/util/provider/machinecontroller/controller_suite_test.go
index 7b6b907d2..814adddc3 100644
--- a/pkg/util/provider/machinecontroller/controller_suite_test.go
+++ b/pkg/util/provider/machinecontroller/controller_suite_test.go
@@ -605,6 +605,7 @@ func createController(
 		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: ""}),
diff --git a/pkg/util/provider/machinecontroller/machine_test.go b/pkg/util/provider/machinecontroller/machine_test.go
index a658641f4..493988e87 100644
--- a/pkg/util/provider/machinecontroller/machine_test.go
+++ b/pkg/util/provider/machinecontroller/machine_test.go
@@ -226,7 +226,7 @@ var _ = Describe("machine", func() {
 				action: machineapi.Machine{
 					Spec: machineapi.MachineSpec{
 						Class: machineapi.ClassSpec{
-							Kind: "AWSMachineClass",
+							Kind: "MachineClass",
 							Name: "aws",
 						},
 					},
@@ -234,6 +234,30 @@ var _ = Describe("machine", func() {
 				expect: field.ErrorList{},
 			}),
 		)
+		DescribeTable("#machine validation fails with no class name",
+			func(data *data) {
+				errList := validation.ValidateMachine(&data.action)
+				Expect(errList).To(Equal(data.expect))
+			},
+			Entry("aws", &data{
+				action: machineapi.Machine{
+					Spec: machineapi.MachineSpec{
+						Class: machineapi.ClassSpec{
+							Kind: "MachineClass",
+							Name: "",
+						},
+					},
+				},
+				expect: field.ErrorList{
+					{
+						Type:     "FieldValueRequired",
+						Field:    "spec.class.name",
+						BadValue: "",
+						Detail:   "Name is required",
+					},
+				},
+			}),
+		)
 	})
 
 	Describe("#ValidateMachineClass", func() {