Repository: syself/cluster-api-provider-hetzner
Pull request #713 (2023-03-30 07:32:41)

:seedling: Update timeouts for E2E tests
**What this PR does / why we need it**:
The timeouts were too high in most of the cases. To make it more understandable, comments are describing what the interval is meant to be used for. Most intervals are not used at all.

**TODOs**:
- [x] squashed commits
- [ ] includes documentation
- [ ] adds unit tests




Patch:
diff --git a/PROJECT b/PROJECT
index e71e2f02..ca8d308f 100644
--- a/PROJECT
+++ b/PROJECT
@@ -134,30 +134,4 @@ resources:
     defaulting: true
     validation: true
     webhookVersion: v1
-- api:
-    crdVersion: v1
-    namespaced: true
-  controller: true
-  domain: cluster.x-k8s.io
-  group: infrastructure
-  kind: HCloudRemediation
-  path: github.com/syself/cluster-api-provider-hetzner/api/v1beta1
-  version: v1beta1
-  webhooks:
-    defaulting: true
-    validation: true
-    webhookVersion: v1
-- api:
-    crdVersion: v1
-    namespaced: true
-  controller: true
-  domain: cluster.x-k8s.io
-  group: infrastructure
-  kind: HCloudRemediationTemplate
-  path: github.com/syself/cluster-api-provider-hetzner/api/v1beta1
-  version: v1beta1
-  webhooks:
-    defaulting: true
-    validation: true
-    webhookVersion: v1
 version: "3"
diff --git a/api/v1beta1/hcloudremediation_types.go b/api/v1beta1/hcloudremediation_types.go
deleted file mode 100644
index db28294f..00000000
--- a/api/v1beta1/hcloudremediation_types.go
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
-Copyright 2022 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package v1beta1
-
-import (
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
-)
-
-const (
-	// HCloudRemediationFinalizer allows HCloudRemediationReconciler to clean up resources associated with HCloudRemediation before
-	// removing it from the apiserver.
-	HCloudRemediationFinalizer = "hcloudremediation.infrastructure.cluster.x-k8s.io"
-
-	// HCloudRebootAnnotation indicates that a bare metal host object should be rebooted.
-	HCloudRebootAnnotation = "reboot.hcloud.infrastructure.cluster.x-k8s.io"
-)
-
-// HCloudRemediationSpec defines the desired state of HCloudRemediation.
-type HCloudRemediationSpec struct {
-	// Strategy field defines remediation strategy.
-	Strategy *RemediationStrategy `json:"strategy,omitempty"`
-}
-
-// HCloudRemediationStatus defines the observed state of HCloudRemediation.
-type HCloudRemediationStatus struct {
-	// Phase represents the current phase of machine remediation.
-	// E.g. Pending, Running, Done etc.
-	// +optional
-	Phase string `json:"phase,omitempty"`
-
-	// RetryCount can be used as a counter during the remediation.
-	// Field can hold number of reboots etc.
-	// +optional
-	RetryCount int `json:"retryCount,omitempty"`
-
-	// LastRemediated identifies when the host was last remediated
-	// +optional
-	LastRemediated *metav1.Time `json:"lastRemediated,omitempty"`
-
-	// Conditions defines current service state of the HCloudRemediation.
-	// +optional
-	Conditions clusterv1.Conditions `json:"conditions,omitempty"`
-}
-
-// +kubebuilder:object:root=true
-// +kubebuilder:subresource:status
-// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
-// +kubebuilder:resource:path=hcloudremediations,scope=Namespaced,categories=cluster-api,shortName=hcr;hcloudremediation
-// +kubebuilder:storageversion
-// +kubebuilder:printcolumn:name="Timeout",type=string,JSONPath=".spec.strategy.timeout",description="Timeout for the remediation"
-// +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=".status.phase",description="Phase of the remediation"
-// +kubebuilder:printcolumn:name="Last Remediated",type=string,JSONPath=".status.lastRemediated",description="Timestamp of the last remediation attempt"
-// +kubebuilder:printcolumn:name="Retry count",type=string,JSONPath=".status.retryCount",description="How many times remediation controller has tried to remediate the node"
-// +kubebuilder:printcolumn:name="Retry limit",type=string,JSONPath=".spec.strategy.retryLimit",description="How many times remediation controller should attempt to remediate the node"
-
-// HCloudRemediation is the Schema for the hcloudremediations API.
-type HCloudRemediation struct {
-	metav1.TypeMeta `json:",inline"`
-	// +optional
-	metav1.ObjectMeta `json:"metadata,omitempty"`
-	// +optional
-	Spec HCloudRemediationSpec `json:"spec,omitempty"`
-	// +optional
-	Status HCloudRemediationStatus `json:"status,omitempty"`
-}
-
-// GetConditions returns the observations of the operational state of the HCloudRemediation resource.
-func (r *HCloudRemediation) GetConditions() clusterv1.Conditions {
-	return r.Status.Conditions
-}
-
-// SetConditions sets the underlying service state of the HCloudRemediation to the predescribed clusterv1.Conditions.
-func (r *HCloudRemediation) SetConditions(conditions clusterv1.Conditions) {
-	r.Status.Conditions = conditions
-}
-
-//+kubebuilder:object:root=true
-
-// HCloudRemediationList contains a list of HCloudRemediation.
-type HCloudRemediationList struct {
-	metav1.TypeMeta `json:",inline"`
-	// +optional
-	metav1.ListMeta `json:"metadata,omitempty"`
-	Items           []HCloudRemediation `json:"items"`
-}
-
-func init() {
-	SchemeBuilder.Register(&HCloudRemediation{}, &HCloudRemediationList{})
-}
diff --git a/api/v1beta1/hcloudremediation_webhook.go b/api/v1beta1/hcloudremediation_webhook.go
deleted file mode 100644
index 920577c6..00000000
--- a/api/v1beta1/hcloudremediation_webhook.go
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-Copyright 2022 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package v1beta1
-
-import (
-	"k8s.io/apimachinery/pkg/runtime"
-	ctrl "sigs.k8s.io/controller-runtime"
-	"sigs.k8s.io/controller-runtime/pkg/webhook"
-)
-
-// SetupWebhookWithManager initializes webhook manager for HCloudRemediation.
-func (r *HCloudRemediation) SetupWebhookWithManager(mgr ctrl.Manager) error {
-	return ctrl.NewWebhookManagedBy(mgr).
-		For(r).
-		Complete()
-}
-
-//+kubebuilder:webhook:path=/mutate-infrastructure-cluster-x-k8s-io-v1beta1-hcloudremediation,mutating=true,failurePolicy=fail,sideEffects=None,groups=infrastructure.cluster.x-k8s.io,resources=hcloudremediations,verbs=create;update,versions=v1beta1,name=mutation.hcloudremediation.infrastructure.cluster.x-k8s.io,admissionReviewVersions={v1,v1beta1}
-
-var _ webhook.Defaulter = &HCloudRemediation{}
-
-// Default implements webhook.Defaulter so a webhook will be registered for the type.
-func (r *HCloudRemediation) Default() {
-}
-
-//+kubebuilder:webhook:path=/validate-infrastructure-cluster-x-k8s-io-v1beta1-hcloudremediation,mutating=false,failurePolicy=fail,sideEffects=None,groups=infrastructure.cluster.x-k8s.io,resources=hcloudremediations,verbs=create;update,versions=v1beta1,name=validation.hcloudremediation.infrastructure.cluster.x-k8s.io,admissionReviewVersions={v1,v1beta1}
-
-var _ webhook.Validator = &HCloudRemediation{}
-
-// ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
-func (r *HCloudRemediation) ValidateCreate() error {
-	return nil
-}
-
-// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
-func (r *HCloudRemediation) ValidateUpdate(old runtime.Object) error {
-	return nil
-}
-
-// ValidateDelete implements webhook.Validator so a webhook will be registered for the type.
-func (r *HCloudRemediation) ValidateDelete() error {
-	return nil
-}
diff --git a/api/v1beta1/hcloudremediationtemplate_types.go b/api/v1beta1/hcloudremediationtemplate_types.go
deleted file mode 100644
index 228c4bbb..00000000
--- a/api/v1beta1/hcloudremediationtemplate_types.go
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
-Copyright 2022 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package v1beta1
-
-import (
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
-// HCloudRemediationTemplateSpec defines the desired state of HCloudRemediationTemplate.
-type HCloudRemediationTemplateSpec struct {
-	Template HCloudRemediationTemplateResource `json:"template"`
-}
-
-// HCloudRemediationTemplateResource describes the data needed to create a HCloudRemediation from a template.
-type HCloudRemediationTemplateResource struct {
-	// Spec is the specification of the desired behavior of the HCloudRemediation.
-	Spec HCloudRemediationSpec `json:"spec"`
-}
-
-// HCloudRemediationTemplateStatus defines the observed state of HCloudRemediationTemplate.
-type HCloudRemediationTemplateStatus struct {
-	// HCloudRemediationStatus defines the observed state of HCloudRemediation
-	Status HCloudRemediationStatus `json:"status"`
-}
-
-// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
-// +kubebuilder:resource:path=hcloudremediationtemplates,scope=Namespaced,categories=cluster-api,shortName=hcrt;hcremediationtemplate;hcremediationtemplates;hcloudrt;hcloudremediationtemplate
-// +kubebuilder:subresource:status
-// +kubebuilder:object:root=true
-// +kubebuilder:storageversion
-// +kubebuilder:printcolumn:name="Strategy",type=string,JSONPath=".spec.template.spec.strategy.type",description="Type of the remediation strategy"
-// +kubebuilder:printcolumn:name="Retry limit",type=string,JSONPath=".spec.template.spec.strategy.retryLimit",description="How many times remediation controller should attempt to remediate the node"
-// +kubebuilder:printcolumn:name="Timeout",type=string,JSONPath=".spec.template.spec.strategy.timeout",description="Timeout for the remediation"
-
-// HCloudRemediationTemplate is the Schema for the hcloudremediationtemplates API.
-type HCloudRemediationTemplate struct {
-	metav1.TypeMeta `json:",inline"`
-	// +optional
-	metav1.ObjectMeta `json:"metadata,omitempty"`
-	// +optional
-	Spec HCloudRemediationTemplateSpec `json:"spec,omitempty"`
-	// +optional
-	Status HCloudRemediationTemplateStatus `json:"status,omitempty"`
-}
-
-//+kubebuilder:object:root=true
-
-// HCloudRemediationTemplateList contains a list of HCloudRemediationTemplate.
-type HCloudRemediationTemplateList struct {
-	metav1.TypeMeta `json:",inline"`
-	// +optional
-	metav1.ListMeta `json:"metadata,omitempty"`
-	Items           []HCloudRemediationTemplate `json:"items"`
-}
-
-func init() {
-	SchemeBuilder.Register(&HCloudRemediationTemplate{}, &HCloudRemediationTemplateList{})
-}
diff --git a/api/v1beta1/hcloudremediationtemplate_webhook.go b/api/v1beta1/hcloudremediationtemplate_webhook.go
deleted file mode 100644
index defff1b9..00000000
--- a/api/v1beta1/hcloudremediationtemplate_webhook.go
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-Copyright 2022 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package v1beta1
-
-import (
-	"k8s.io/apimachinery/pkg/runtime"
-	ctrl "sigs.k8s.io/controller-runtime"
-	"sigs.k8s.io/controller-runtime/pkg/webhook"
-)
-
-// SetupWebhookWithManager initializes webhook manager for HCloudRemediationTemplate.
-func (r *HCloudRemediationTemplate) SetupWebhookWithManager(mgr ctrl.Manager) error {
-	return ctrl.NewWebhookManagedBy(mgr).
-		For(r).
-		Complete()
-}
-
-//+kubebuilder:webhook:path=/mutate-infrastructure-cluster-x-k8s-io-v1beta1-hcloudremediationtemplate,mutating=true,failurePolicy=fail,sideEffects=None,groups=infrastructure.cluster.x-k8s.io,resources=hcloudremediationtemplates,verbs=create;update,versions=v1beta1,name=mhcloudremediationtemplate.kb.io,admissionReviewVersions=v1
-
-var _ webhook.Defaulter = &HCloudRemediationTemplate{}
-
-// Default implements webhook.Defaulter so a webhook will be registered for the type.
-func (r *HCloudRemediationTemplate) Default() {
-}
-
-//+kubebuilder:webhook:path=/validate-infrastructure-cluster-x-k8s-io-v1beta1-hcloudremediationtemplate,mutating=false,failurePolicy=fail,sideEffects=None,groups=infrastructure.cluster.x-k8s.io,resources=hcloudremediationtemplates,verbs=create;update,versions=v1beta1,name=vhcloudremediationtemplate.kb.io,admissionReviewVersions=v1
-
-var _ webhook.Validator = &HCloudRemediationTemplate{}
-
-// ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
-func (r *HCloudRemediationTemplate) ValidateCreate() error {
-	return nil
-}
-
-// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
-func (r *HCloudRemediationTemplate) ValidateUpdate(old runtime.Object) error {
-	return nil
-}
-
-// ValidateDelete implements webhook.Validator so a webhook will be registered for the type.
-func (r *HCloudRemediationTemplate) ValidateDelete() error {
-	return nil
-}
diff --git a/api/v1beta1/hetznerbaremetalremediation_types.go b/api/v1beta1/hetznerbaremetalremediation_types.go
index 4044eb40..f7f1968b 100644
--- a/api/v1beta1/hetznerbaremetalremediation_types.go
+++ b/api/v1beta1/hetznerbaremetalremediation_types.go
@@ -20,6 +20,9 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
+// RemediationType defines the type of remediation.
+type RemediationType string
+
 const (
 	// RemediationFinalizer allows HetznerBareMetalRemediationReconciler to clean up resources associated with HetznerBareMetalRemediation before
 	// removing it from the apiserver.
@@ -27,6 +30,20 @@ const (
 
 	// RebootAnnotation indicates that a bare metal host object should be rebooted.
 	RebootAnnotation = "reboot.hetznerbaremetalhost.infrastructure.cluster.x-k8s.io"
+
+	// RebootRemediationStrategy sets RemediationType to Reboot.
+	RebootRemediationStrategy RemediationType = "Reboot"
+)
+
+const (
+	// PhaseRunning represents the running state during remediation.
+	PhaseRunning = "Running"
+
+	// PhaseWaiting represents the state during remediation when the controller has done its job but still waiting for the result of the last remediation step.
+	PhaseWaiting = "Waiting"
+
+	// PhaseDeleting represents the state where host remediation has failed and the controller is deleting the unhealthy Machine object from the cluster.
+	PhaseDeleting = "Deleting machine"
 )
 
 // HetznerBareMetalRemediationSpec defines the desired state of HetznerBareMetalRemediation.
@@ -35,8 +52,24 @@ type HetznerBareMetalRemediationSpec struct {
 	Strategy *RemediationStrategy `json:"strategy,omitempty"`
 }
 
+// RemediationStrategy describes how to remediate machines.
+type RemediationStrategy struct {
+	// Type of remediation.
+	// +kubebuilder:default=Reboot
+	// +optional
+	Type RemediationType `json:"type,omitempty"`
+
+	// Sets maximum number of remediation retries.
+	// +optional
+	RetryLimit int `json:"retryLimit,omitempty"`
+
+	// Sets the timeout between remediation retries.
+	Timeout *metav1.Duration `json:"timeout"`
+}
+
 // HetznerBareMetalRemediationStatus defines the observed state of HetznerBareMetalRemediation.
 type HetznerBareMetalRemediationStatus struct {
+
 	// Phase represents the current phase of machine remediation.
 	// E.g. Pending, Running, Done etc.
 	// +optional
diff --git a/api/v1beta1/remediation_types.go b/api/v1beta1/remediation_types.go
deleted file mode 100644
index ddb337b8..00000000
--- a/api/v1beta1/remediation_types.go
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package v1beta1
-
-import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-
-// RemediationType defines the type of remediation.
-type RemediationType string
-
-const (
-	// RemediationTypeReboot sets RemediationType to Reboot.
-	RemediationTypeReboot RemediationType = "Reboot"
-)
-
-const (
-	// PhaseRunning represents the running state during remediation.
-	PhaseRunning = "Running"
-
-	// PhaseWaiting represents the state during remediation when the controller has done its job but still waiting for the result of the last remediation step.
-	PhaseWaiting = "Waiting"
-
-	// PhaseDeleting represents the state where host remediation has failed and the controller is deleting the unhealthy Machine object from the cluster.
-	PhaseDeleting = "Deleting machine"
-)
-
-// RemediationStrategy describes how to remediate machines.
-type RemediationStrategy struct {
-	// Type of remediation.
-	// +kubebuilder:default=Reboot
-	// +optional
-	Type RemediationType `json:"type,omitempty"`
-
-	// Sets maximum number of remediation retries.
-	// +optional
-	RetryLimit int `json:"retryLimit,omitempty"`
-
-	// Sets the timeout between remediation retries.
-	Timeout *metav1.Duration `json:"timeout"`
-}
diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go
index d71b07ae..c9bd370f 100644
--- a/api/v1beta1/zz_generated.deepcopy.go
+++ b/api/v1beta1/zz_generated.deepcopy.go
@@ -424,218 +424,6 @@ func (in *HCloudPlacementGroupStatus) DeepCopy() *HCloudPlacementGroupStatus {
 	return out
 }
 
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *HCloudRemediation) DeepCopyInto(out *HCloudRemediation) {
-	*out = *in
-	out.TypeMeta = in.TypeMeta
-	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-	in.Spec.DeepCopyInto(&out.Spec)
-	in.Status.DeepCopyInto(&out.Status)
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HCloudRemediation.
-func (in *HCloudRemediation) DeepCopy() *HCloudRemediation {
-	if in == nil {
-		return nil
-	}
-	out := new(HCloudRemediation)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *HCloudRemediation) DeepCopyObject() runtime.Object {
-	if c := in.DeepCopy(); c != nil {
-		return c
-	}
-	return nil
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *HCloudRemediationList) DeepCopyInto(out *HCloudRemediationList) {
-	*out = *in
-	out.TypeMeta = in.TypeMeta
-	in.ListMeta.DeepCopyInto(&out.ListMeta)
-	if in.Items != nil {
-		in, out := &in.Items, &out.Items
-		*out = make([]HCloudRemediation, len(*in))
-		for i := range *in {
-			(*in)[i].DeepCopyInto(&(*out)[i])
-		}
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HCloudRemediationList.
-func (in *HCloudRemediationList) DeepCopy() *HCloudRemediationList {
-	if in == nil {
-		return nil
-	}
-	out := new(HCloudRemediationList)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *HCloudRemediationList) DeepCopyObject() runtime.Object {
-	if c := in.DeepCopy(); c != nil {
-		return c
-	}
-	return nil
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *HCloudRemediationSpec) DeepCopyInto(out *HCloudRemediationSpec) {
-	*out = *in
-	if in.Strategy != nil {
-		in, out := &in.Strategy, &out.Strategy
-		*out = new(RemediationStrategy)
-		(*in).DeepCopyInto(*out)
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HCloudRemediationSpec.
-func (in *HCloudRemediationSpec) DeepCopy() *HCloudRemediationSpec {
-	if in == nil {
-		return nil
-	}
-	out := new(HCloudRemediationSpec)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *HCloudRemediationStatus) DeepCopyInto(out *HCloudRemediationStatus) {
-	*out = *in
-	if in.LastRemediated != nil {
-		in, out := &in.LastRemediated, &out.LastRemediated
-		*out = (*in).DeepCopy()
-	}
-	if in.Conditions != nil {
-		in, out := &in.Conditions, &out.Conditions
-		*out = make(apiv1beta1.Conditions, len(*in))
-		for i := range *in {
-			(*in)[i].DeepCopyInto(&(*out)[i])
-		}
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HCloudRemediationStatus.
-func (in *HCloudRemediationStatus) DeepCopy() *HCloudRemediationStatus {
-	if in == nil {
-		return nil
-	}
-	out := new(HCloudRemediationStatus)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *HCloudRemediationTemplate) DeepCopyInto(out *HCloudRemediationTemplate) {
-	*out = *in
-	out.TypeMeta = in.TypeMeta
-	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-	in.Spec.DeepCopyInto(&out.Spec)
-	in.Status.DeepCopyInto(&out.Status)
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HCloudRemediationTemplate.
-func (in *HCloudRemediationTemplate) DeepCopy() *HCloudRemediationTemplate {
-	if in == nil {
-		return nil
-	}
-	out := new(HCloudRemediationTemplate)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *HCloudRemediationTemplate) DeepCopyObject() runtime.Object {
-	if c := in.DeepCopy(); c != nil {
-		return c
-	}
-	return nil
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *HCloudRemediationTemplateList) DeepCopyInto(out *HCloudRemediationTemplateList) {
-	*out = *in
-	out.TypeMeta = in.TypeMeta
-	in.ListMeta.DeepCopyInto(&out.ListMeta)
-	if in.Items != nil {
-		in, out := &in.Items, &out.Items
-		*out = make([]HCloudRemediationTemplate, len(*in))
-		for i := range *in {
-			(*in)[i].DeepCopyInto(&(*out)[i])
-		}
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HCloudRemediationTemplateList.
-func (in *HCloudRemediationTemplateList) DeepCopy() *HCloudRemediationTemplateList {
-	if in == nil {
-		return nil
-	}
-	out := new(HCloudRemediationTemplateList)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *HCloudRemediationTemplateList) DeepCopyObject() runtime.Object {
-	if c := in.DeepCopy(); c != nil {
-		return c
-	}
-	return nil
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *HCloudRemediationTemplateResource) DeepCopyInto(out *HCloudRemediationTemplateResource) {
-	*out = *in
-	in.Spec.DeepCopyInto(&out.Spec)
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HCloudRemediationTemplateResource.
-func (in *HCloudRemediationTemplateResource) DeepCopy() *HCloudRemediationTemplateResource {
-	if in == nil {
-		return nil
-	}
-	out := new(HCloudRemediationTemplateResource)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *HCloudRemediationTemplateSpec) DeepCopyInto(out *HCloudRemediationTemplateSpec) {
-	*out = *in
-	in.Template.DeepCopyInto(&out.Template)
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HCloudRemediationTemplateSpec.
-func (in *HCloudRemediationTemplateSpec) DeepCopy() *HCloudRemediationTemplateSpec {
-	if in == nil {
-		return nil
-	}
-	out := new(HCloudRemediationTemplateSpec)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *HCloudRemediationTemplateStatus) DeepCopyInto(out *HCloudRemediationTemplateStatus) {
-	*out = *in
-	in.Status.DeepCopyInto(&out.Status)
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HCloudRemediationTemplateStatus.
-func (in *HCloudRemediationTemplateStatus) DeepCopy() *HCloudRemediationTemplateStatus {
-	if in == nil {
-		return nil
-	}
-	out := new(HCloudRemediationTemplateStatus)
-	in.DeepCopyInto(out)
-	return out
-}
-
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *HardwareDetails) DeepCopyInto(out *HardwareDetails) {
 	*out = *in
diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_hcloudremediations.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_hcloudremediations.yaml
deleted file mode 100644
index 8e7730ad..00000000
--- a/config/crd/bases/infrastructure.cluster.x-k8s.io_hcloudremediations.yaml
+++ /dev/null
@@ -1,148 +0,0 @@
----
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
-metadata:
-  annotations:
-    controller-gen.kubebuilder.io/version: v0.10.0
-  creationTimestamp: null
-  name: hcloudremediations.infrastructure.cluster.x-k8s.io
-spec:
-  group: infrastructure.cluster.x-k8s.io
-  names:
-    categories:
-    - cluster-api
-    kind: HCloudRemediation
-    listKind: HCloudRemediationList
-    plural: hcloudremediations
-    shortNames:
-    - hcr
-    - hcloudremediation
-    singular: hcloudremediation
-  scope: Namespaced
-  versions:
-  - additionalPrinterColumns:
-    - description: Timeout for the remediation
-      jsonPath: .spec.strategy.timeout
-      name: Timeout
-      type: string
-    - description: Phase of the remediation
-      jsonPath: .status.phase
-      name: Phase
-      type: string
-    - description: Timestamp of the last remediation attempt
-      jsonPath: .status.lastRemediated
-      name: Last Remediated
-      type: string
-    - description: How many times remediation controller has tried to remediate the
-        node
-      jsonPath: .status.retryCount
-      name: Retry count
-      type: string
-    - description: How many times remediation controller should attempt to remediate
-        the node
-      jsonPath: .spec.strategy.retryLimit
-      name: Retry limit
-      type: string
-    name: v1beta1
-    schema:
-      openAPIV3Schema:
-        description: HCloudRemediation is the Schema for the hcloudremediations API.
-        properties:
-          apiVersion:
-            description: 'APIVersion defines the versioned schema of this representation
-              of an object. Servers should convert recognized schemas to the latest
-              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
-            type: string
-          kind:
-            description: 'Kind is a string value representing the REST resource this
-              object represents. Servers may infer this from the endpoint the client
-              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
-            type: string
-          metadata:
-            type: object
-          spec:
-            description: HCloudRemediationSpec defines the desired state of HCloudRemediation.
-            properties:
-              strategy:
-                description: Strategy field defines remediation strategy.
-                properties:
-                  retryLimit:
-                    description: Sets maximum number of remediation retries.
-                    type: integer
-                  timeout:
-                    description: Sets the timeout between remediation retries.
-                    type: string
-                  type:
-                    default: Reboot
-                    description: Type of remediation.
-                    type: string
-                required:
-                - timeout
-                type: object
-            type: object
-          status:
-            description: HCloudRemediationStatus defines the observed state of HCloudRemediation.
-            properties:
-              conditions:
-                description: Conditions defines current service state of the HCloudRemediation.
-                items:
-                  description: Condition defines an observation of a Cluster API resource
-                    operational state.
-                  properties:
-                    lastTransitionTime:
-                      description: Last time the condition transitioned from one status
-                        to another. This should be when the underlying condition changed.
-                        If that is not known, then using the time when the API field
-                        changed is acceptable.
-                      format: date-time
-                      type: string
-                    message:
-                      description: A human readable message indicating details about
-                        the transition. This field may be empty.
-                      type: string
-                    reason:
-                      description: The reason for the condition's last transition
-                        in CamelCase. The specific API may choose whether or not this
-                        field is considered a guaranteed API. This field may not be
-                        empty.
-                      type: string
-                    severity:
-                      description: Severity provides an explicit classification of
-                        Reason code, so the users or machines can immediately understand
-                        the current situation and act accordingly. The Severity field
-                        MUST be set only when Status=False.
-                      type: string
-                    status:
-                      description: Status of the condition, one of True, False, Unknown.
-                      type: string
-                    type:
-                      description: Type of condition in CamelCase or in foo.example.com/CamelCase.
-                        Many .condition.type values are consistent across resources
-                        like Available, but because arbitrary conditions can be useful
-                        (see .node.status.conditions), the ability to deconflict is
-                        important.
-                      type: string
-                  required:
-                  - lastTransitionTime
-                  - status
-                  - type
-                  type: object
-                type: array
-              lastRemediated:
-                description: LastRemediated identifies when the host was last remediated
-                format: date-time
-                type: string
-              phase:
-                description: Phase represents the current phase of machine remediation.
-                  E.g. Pending, Running, Done etc.
-                type: string
-              retryCount:
-                description: RetryCount can be used as a counter during the remediation.
-                  Field can hold number of reboots etc.
-                type: integer
-            type: object
-        type: object
-    served: true
-    storage: true
-    subresources:
-      status: {}
diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_hcloudremediationtemplates.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_hcloudremediationtemplates.yaml
deleted file mode 100644
index af2211c1..00000000
--- a/config/crd/bases/infrastructure.cluster.x-k8s.io_hcloudremediationtemplates.yaml
+++ /dev/null
@@ -1,168 +0,0 @@
----
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
-metadata:
-  annotations:
-    controller-gen.kubebuilder.io/version: v0.10.0
-  creationTimestamp: null
-  name: hcloudremediationtemplates.infrastructure.cluster.x-k8s.io
-spec:
-  group: infrastructure.cluster.x-k8s.io
-  names:
-    categories:
-    - cluster-api
-    kind: HCloudRemediationTemplate
-    listKind: HCloudRemediationTemplateList
-    plural: hcloudremediationtemplates
-    shortNames:
-    - hcrt
-    - hcremediationtemplate
-    - hcremediationtemplates
-    - hcloudrt
-    - hcloudremediationtemplate
-    singular: hcloudremediationtemplate
-  scope: Namespaced
-  versions:
-  - additionalPrinterColumns:
-    - description: Type of the remediation strategy
-      jsonPath: .spec.template.spec.strategy.type
-      name: Strategy
-      type: string
-    - description: How many times remediation controller should attempt to remediate
-        the node
-      jsonPath: .spec.template.spec.strategy.retryLimit
-      name: Retry limit
-      type: string
-    - description: Timeout for the remediation
-      jsonPath: .spec.template.spec.strategy.timeout
-      name: Timeout
-      type: string
-    name: v1beta1
-    schema:
-      openAPIV3Schema:
-        description: HCloudRemediationTemplate is the Schema for the hcloudremediationtemplates
-          API.
-        properties:
-          apiVersion:
-            description: 'APIVersion defines the versioned schema of this representation
-              of an object. Servers should convert recognized schemas to the latest
-              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
-            type: string
-          kind:
-            description: 'Kind is a string value representing the REST resource this
-              object represents. Servers may infer this from the endpoint the client
-              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
-            type: string
-          metadata:
-            type: object
-          spec:
-            description: HCloudRemediationTemplateSpec defines the desired state of
-              HCloudRemediationTemplate.
-            properties:
-              template:
-                description: HCloudRemediationTemplateResource describes the data
-                  needed to create a HCloudRemediation from a template.
-                properties:
-                  spec:
-                    description: Spec is the specification of the desired behavior
-                      of the HCloudRemediation.
-                    properties:
-                      strategy:
-                        description: Strategy field defines remediation strategy.
-                        properties:
-                          retryLimit:
-                            description: Sets maximum number of remediation retries.
-                            type: integer
-                          timeout:
-                            description: Sets the timeout between remediation retries.
-                            type: string
-                          type:
-                            default: Reboot
-                            description: Type of remediation.
-                            type: string
-                        required:
-                        - timeout
-                        type: object
-                    type: object
-                required:
-                - spec
-                type: object
-            required:
-            - template
-            type: object
-          status:
-            description: HCloudRemediationTemplateStatus defines the observed state
-              of HCloudRemediationTemplate.
-            properties:
-              status:
-                description: HCloudRemediationStatus defines the observed state of
-                  HCloudRemediation
-                properties:
-                  conditions:
-                    description: Conditions defines current service state of the HCloudRemediation.
-                    items:
-                      description: Condition defines an observation of a Cluster API
-                        resource operational state.
-                      properties:
-                        lastTransitionTime:
-                          description: Last time the condition transitioned from one
-                            status to another. This should be when the underlying
-                            condition changed. If that is not known, then using the
-                            time when the API field changed is acceptable.
-                          format: date-time
-                          type: string
-                        message:
-                          description: A human readable message indicating details
-                            about the transition. This field may be empty.
-                          type: string
-                        reason:
-                          description: The reason for the condition's last transition
-                            in CamelCase. The specific API may choose whether or not
-                            this field is considered a guaranteed API. This field
-                            may not be empty.
-                          type: string
-                        severity:
-                          description: Severity provides an explicit classification
-                            of Reason code, so the users or machines can immediately
-                            understand the current situation and act accordingly.
-                            The Severity field MUST be set only when Status=False.
-                          type: string
-                        status:
-                          description: Status of the condition, one of True, False,
-                            Unknown.
-                          type: string
-                        type:
-                          description: Type of condition in CamelCase or in foo.example.com/CamelCase.
-                            Many .condition.type values are consistent across resources
-                            like Available, but because arbitrary conditions can be
-                            useful (see .node.status.conditions), the ability to deconflict
-                            is important.
-                          type: string
-                      required:
-                      - lastTransitionTime
-                      - status
-                      - type
-                      type: object
-                    type: array
-                  lastRemediated:
-                    description: LastRemediated identifies when the host was last
-                      remediated
-                    format: date-time
-                    type: string
-                  phase:
-                    description: Phase represents the current phase of machine remediation.
-                      E.g. Pending, Running, Done etc.
-                    type: string
-                  retryCount:
-                    description: RetryCount can be used as a counter during the remediation.
-                      Field can hold number of reboots etc.
-                    type: integer
-                type: object
-            required:
-            - status
-            type: object
-        type: object
-    served: true
-    storage: true
-    subresources:
-      status: {}
diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml
index 9f29f608..599df517 100644
--- a/config/crd/kustomization.yaml
+++ b/config/crd/kustomization.yaml
@@ -14,8 +14,6 @@ resources:
   - bases/infrastructure.cluster.x-k8s.io_hetznerbaremetalremediationtemplates.yaml
   - bases/infrastructure.cluster.x-k8s.io_hetznerbaremetalhosts.yaml
   - bases/infrastructure.cluster.x-k8s.io_hetznerbaremetalremediations.yaml
-  - bases/infrastructure.cluster.x-k8s.io_hcloudremediationtemplates.yaml
-  - bases/infrastructure.cluster.x-k8s.io_hcloudremediations.yaml
 #+kubebuilder:scaffold:crdkustomizeresource
 
 patchesStrategicMerge:
@@ -30,8 +28,6 @@ patchesStrategicMerge:
   - patches/webhook_in_hetznerbaremetalremediationtemplates.yaml
   - patches/webhook_in_hetznerbaremetalhosts.yaml
   - patches/webhook_in_hetznerbaremetalremediations.yaml
-  - patches/webhook_in_hcloudremediationtemplates.yaml
-  - patches/webhook_in_hcloudremediations.yaml
   #+kubebuilder:scaffold:crdkustomizewebhookpatch
 
   # [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix.
@@ -45,8 +41,6 @@ patchesStrategicMerge:
   - patches/cainjection_in_hetznerbaremetalremediationtemplates.yaml
   - patches/cainjection_in_hetznerbaremetalhosts.yaml
   - patches/cainjection_in_hetznerbaremetalremediations.yaml
-  - patches/cainjection_in_hcloudremediationtemplates.yaml
-  - patches/cainjection_in_hcloudremediations.yaml
 #+kubebuilder:scaffold:crdkustomizecainjectionpatch
 
 # the following config is for teaching kustomize how to do kustomization for CRDs.
diff --git a/config/crd/patches/cainjection_in_hcloudremediations.yaml b/config/crd/patches/cainjection_in_hcloudremediations.yaml
deleted file mode 100644
index 65b90776..00000000
--- a/config/crd/patches/cainjection_in_hcloudremediations.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-# The following patch adds a directive for certmanager to inject CA into the CRD
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
-metadata:
-  annotations:
-    cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
-  name: hcloudremediations.infrastructure.cluster.x-k8s.io
diff --git a/config/crd/patches/cainjection_in_hcloudremediationtemplates.yaml b/config/crd/patches/cainjection_in_hcloudremediationtemplates.yaml
deleted file mode 100644
index f8a528f5..00000000
--- a/config/crd/patches/cainjection_in_hcloudremediationtemplates.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-# The following patch adds a directive for certmanager to inject CA into the CRD
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
-metadata:
-  annotations:
-    cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
-  name: hcloudremediationtemplates.infrastructure.cluster.x-k8s.io
diff --git a/config/crd/patches/webhook_in_hcloudremediations.yaml b/config/crd/patches/webhook_in_hcloudremediations.yaml
deleted file mode 100644
index 6fd58525..00000000
--- a/config/crd/patches/webhook_in_hcloudremediations.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-# The following patch enables a conversion webhook for the CRD
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
-metadata:
-  name: hcloudremediations.infrastructure.cluster.x-k8s.io
-spec:
-  conversion:
-    strategy: Webhook
-    webhook:
-      clientConfig:
-        service:
-          namespace: system
-          name: webhook-service
-          path: /convert
-      conversionReviewVersions:
-      - v1
diff --git a/config/crd/patches/webhook_in_hcloudremediationtemplates.yaml b/config/crd/patches/webhook_in_hcloudremediationtemplates.yaml
deleted file mode 100644
index 0d852fc7..00000000
--- a/config/crd/patches/webhook_in_hcloudremediationtemplates.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-# The following patch enables a conversion webhook for the CRD
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
-metadata:
-  name: hcloudremediationtemplates.infrastructure.cluster.x-k8s.io
-spec:
-  conversion:
-    strategy: Webhook
-    webhook:
-      clientConfig:
-        service:
-          namespace: system
-          name: webhook-service
-          path: /convert
-      conversionReviewVersions:
-      - v1
diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml
index 910397fc..3d10916c 100644
--- a/config/rbac/role.yaml
+++ b/config/rbac/role.yaml
@@ -113,32 +113,6 @@ rules:
   - get
   - patch
   - update
-- apiGroups:
-  - infrastructure.cluster.x-k8s.io
-  resources:
-  - hcloudremediations
-  verbs:
-  - create
-  - delete
-  - get
-  - list
-  - patch
-  - update
-  - watch
-- apiGroups:
-  - infrastructure.cluster.x-k8s.io
-  resources:
-  - hcloudremediations/finalizers
-  verbs:
-  - update
-- apiGroups:
-  - infrastructure.cluster.x-k8s.io
-  resources:
-  - hcloudremediations/status
-  verbs:
-  - get
-  - patch
-  - update
 - apiGroups:
   - infrastructure.cluster.x-k8s.io
   resources:
diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml
index f91578da..8fa4b114 100644
--- a/config/webhook/manifests.yaml
+++ b/config/webhook/manifests.yaml
@@ -26,47 +26,6 @@ webhooks:
     resources:
     - hcloudmachines
   sideEffects: None
-- admissionReviewVersions:
-  - v1
-  - v1beta1
-  clientConfig:
-    service:
-      name: webhook-service
-      namespace: system
-      path: /mutate-infrastructure-cluster-x-k8s-io-v1beta1-hcloudremediation
-  failurePolicy: Fail
-  name: mutation.hcloudremediation.infrastructure.cluster.x-k8s.io
-  rules:
-  - apiGroups:
-    - infrastructure.cluster.x-k8s.io
-    apiVersions:
-    - v1beta1
-    operations:
-    - CREATE
-    - UPDATE
-    resources:
-    - hcloudremediations
-  sideEffects: None
-- admissionReviewVersions:
-  - v1
-  clientConfig:
-    service:
-      name: webhook-service
-      namespace: system
-      path: /mutate-infrastructure-cluster-x-k8s-io-v1beta1-hcloudremediationtemplate
-  failurePolicy: Fail
-  name: mhcloudremediationtemplate.kb.io
-  rules:
-  - apiGroups:
-    - infrastructure.cluster.x-k8s.io
-    apiVersions:
-    - v1beta1
-    operations:
-    - CREATE
-    - UPDATE
-    resources:
-    - hcloudremediationtemplates
-  sideEffects: None
 - admissionReviewVersions:
   - v1
   - v1beta1
@@ -220,47 +179,6 @@ webhooks:
     resources:
     - hcloudmachinetemplates
   sideEffects: None
-- admissionReviewVersions:
-  - v1
-  - v1beta1
-  clientConfig:
-    service:
-      name: webhook-service
-      namespace: system
-      path: /validate-infrastructure-cluster-x-k8s-io-v1beta1-hcloudremediation
-  failurePolicy: Fail
-  name: validation.hcloudremediation.infrastructure.cluster.x-k8s.io
-  rules:
-  - apiGroups:
-    - infrastructure.cluster.x-k8s.io
-    apiVersions:
-    - v1beta1
-    operations:
-    - CREATE
-    - UPDATE
-    resources:
-    - hcloudremediations
-  sideEffects: None
-- admissionReviewVersions:
-  - v1
-  clientConfig:
-    service:
-      name: webhook-service
-      namespace: system
-      path: /validate-infrastructure-cluster-x-k8s-io-v1beta1-hcloudremediationtemplate
-  failurePolicy: Fail
-  name: vhcloudremediationtemplate.kb.io
-  rules:
-  - apiGroups:
-    - infrastructure.cluster.x-k8s.io
-    apiVersions:
-    - v1beta1
-    operations:
-    - CREATE
-    - UPDATE
-    resources:
-    - hcloudremediationtemplates
-  sideEffects: None
 - admissionReviewVersions:
   - v1
   - v1beta1
diff --git a/controllers/hcloudmachine_controller.go b/controllers/hcloudmachine_controller.go
index 7ad23565..e067bed6 100644
--- a/controllers/hcloudmachine_controller.go
+++ b/controllers/hcloudmachine_controller.go
@@ -163,14 +163,11 @@ func (r *HCloudMachineReconciler) reconcileDelete(ctx context.Context, machineSc
 	hcloudMachine := machineScope.HCloudMachine
 
 	// Delete servers.
-	result, err := server.NewService(machineScope).Delete(ctx)
-	if err != nil {
-		return result, fmt.Errorf("failed to delete servers for HCloudMachine %s/%s: %w", hcloudMachine.Namespace, hcloudMachine.Name, err)
-	}
-	emptyResult := reconcile.Result{}
-	if result != emptyResult {
-		return result, nil
+	if result, brk, err := breakReconcile(server.NewService(machineScope).Delete(ctx)); brk {
+		return result, fmt.Errorf("failed to delete servers for HCloudMachine %s/%s: %w",
+			hcloudMachine.Namespace, hcloudMachine.Name, err)
 	}
+
 	// Machine is deleted so remove the finalizer.
 	controllerutil.RemoveFinalizer(machineScope.HCloudMachine, infrav1.MachineFinalizer)
 
@@ -190,13 +187,12 @@ func (r *HCloudMachineReconciler) reconcileNormal(ctx context.Context, machineSc
 	}
 
 	// reconcile server
-	result, err := server.NewService(machineScope).Reconcile(ctx)
-	if err != nil {
+	if result, brk, err := breakReconcile(server.NewService(machineScope).Reconcile(ctx)); brk {
 		return result, fmt.Errorf("failed to reconcile server for HCloudMachine %s/%s: %w",
 			hcloudMachine.Namespace, hcloudMachine.Name, err)
 	}
 
-	return result, nil
+	return reconcile.Result{}, nil
 }
 
 // SetupWithManager sets up the controller with the Manager.
diff --git a/controllers/hcloudmachinetemplate_controller.go b/controllers/hcloudmachinetemplate_controller.go
index 077772f7..320294d8 100644
--- a/controllers/hcloudmachinetemplate_controller.go
+++ b/controllers/hcloudmachinetemplate_controller.go
@@ -123,7 +123,7 @@ func (r *HCloudMachineTemplateReconciler) Reconcile(ctx context.Context, req rec
 
 func (r *HCloudMachineTemplateReconciler) reconcile(ctx context.Context, machineTemplateScope *scope.HCloudMachineTemplateScope) (reconcile.Result, error) {
 	machineTemplateScope.Info("Reconciling HCloudMachineTemplate")
-	hcloudMachineTemplate := machineTemplateScope.HCloudMachineTemplate
+	hcloudMachine := machineTemplateScope.HCloudMachineTemplate
 
 	// If the HCloudMachineTemplate doesn't have our finalizer, add it.
 	controllerutil.AddFinalizer(machineTemplateScope.HCloudMachineTemplate, infrav1.MachineFinalizer)
@@ -134,9 +134,9 @@ func (r *HCloudMachineTemplateReconciler) reconcile(ctx context.Context, machine
 	}
 
 	// reconcile machine template
-	if err := machinetemplate.NewService(machineTemplateScope).Reconcile(ctx); err != nil {
-		return reconcile.Result{}, fmt.Errorf("failed to reconcile machine template for HCloudMachineTemplate %s/%s: %w",
-			hcloudMachineTemplate.Namespace, hcloudMachineTemplate.Name, err)
+	if result, brk, err := breakReconcile(machinetemplate.NewService(machineTemplateScope).Reconcile(ctx)); brk {
+		return result, fmt.Errorf("failed to reconcile machine template for HCloudMachineTemplate %s/%s: %w",
+			hcloudMachine.Namespace, hcloudMachine.Name, err)
 	}
 
 	return reconcile.Result{}, nil
diff --git a/controllers/hcloudremediation_controller.go b/controllers/hcloudremediation_controller.go
deleted file mode 100644
index 9e7d6755..00000000
--- a/controllers/hcloudremediation_controller.go
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
-Copyright 2022 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package controllers
-
-import (
-	"context"
-	"fmt"
-	"time"
-
-	infrav1 "github.com/syself/cluster-api-provider-hetzner/api/v1beta1"
-	"github.com/syself/cluster-api-provider-hetzner/pkg/scope"
-	secretutil "github.com/syself/cluster-api-provider-hetzner/pkg/secrets"
-	hcloudclient "github.com/syself/cluster-api-provider-hetzner/pkg/services/hcloud/client"
-	hcloudremediation "github.com/syself/cluster-api-provider-hetzner/pkg/services/hcloud/remediation"
-	apierrors "k8s.io/apimachinery/pkg/api/errors"
-	"k8s.io/klog/v2"
-	"sigs.k8s.io/cluster-api/util"
-	"sigs.k8s.io/cluster-api/util/annotations"
-	"sigs.k8s.io/cluster-api/util/patch"
-	"sigs.k8s.io/cluster-api/util/predicates"
-	ctrl "sigs.k8s.io/controller-runtime"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-	"sigs.k8s.io/controller-runtime/pkg/controller"
-	"sigs.k8s.io/controller-runtime/pkg/reconcile"
-)
-
-// HCloudRemediationReconciler reconciles a HCloudRemediation object.
-type HCloudRemediationReconciler struct {
-	client.Client
-	APIReader           client.Reader
-	HCloudClientFactory hcloudclient.Factory
-	WatchFilterValue    string
-}
-
-//+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=hcloudremediations,verbs=get;list;watch;create;update;patch;delete
-//+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=hcloudremediations/status,verbs=get;update;patch
-//+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=hcloudremediations/finalizers,verbs=update
-//+kubebuilder:rbac:groups=cluster.x-k8s.io,resources=machines;machines/status,verbs=get;update;patch
-
-// Reconcile reconciles the hetznerHCloudRemediation object.
-func (r *HCloudRemediationReconciler) Reconcile(ctx context.Context, req reconcile.Request) (_ reconcile.Result, reterr error) {
-	log := ctrl.LoggerFrom(ctx)
-
-	// Fetch the Hetzner bare metal host instance.
-	hcloudRemediation := &infrav1.HCloudRemediation{}
-	err := r.Get(ctx, req.NamespacedName, hcloudRemediation)
-	if err != nil {
-		if apierrors.IsNotFound(err) {
-			return reconcile.Result{}, nil
-		}
-		return reconcile.Result{}, err
-	}
-
-	log = log.WithValues("HCloudRemediation", klog.KObj(hcloudRemediation))
-
-	// Fetch the Machine.
-	machine, err := util.GetOwnerMachine(ctx, r.Client, hcloudRemediation.ObjectMeta)
-	if err != nil {
-		return reconcile.Result{}, err
-	}
-	if machine == nil {
-		log.Info("Machine Controller has not yet set OwnerRef")
-		return reconcile.Result{}, nil
-	}
-
-	log = log.WithValues("Machine", klog.KObj(machine))
-
-	// Fetch the HCloudMachine instance.
-	hcloudMachine := &infrav1.HCloudMachine{}
-
-	key := client.ObjectKey{
-		Name:      machine.Spec.InfrastructureRef.Name,
-		Namespace: machine.Spec.InfrastructureRef.Namespace,
-	}
-
-	if err := r.Get(ctx, key, hcloudMachine); err != nil {
-		if apierrors.IsNotFound(err) {
-			return reconcile.Result{}, nil
-		}
-		return reconcile.Result{}, err
-	}
-
-	log = log.WithValues("HCloudMachine", klog.KObj(hcloudMachine))
-
-	// Fetch the Cluster.
-	cluster, err := util.GetClusterFromMetadata(ctx, r.Client, machine.ObjectMeta)
-	if err != nil {
-		log.Info("Machine is missing cluster label or cluster does not exist")
-		return reconcile.Result{}, nil
-	}
-
-	if annotations.IsPaused(cluster, hcloudMachine) {
-		log.Info("HCloudMachine or linked Cluster is marked as paused. Won't reconcile")
-		return reconcile.Result{}, nil
-	}
-
-	log = log.WithValues("Cluster", klog.KObj(cluster))
-
-	hetznerCluster := &infrav1.HetznerCluster{}
-
-	hetznerClusterName := client.ObjectKey{
-		Namespace: hcloudMachine.Namespace,
-		Name:      cluster.Spec.InfrastructureRef.Name,
-	}
-	if err := r.Client.Get(ctx, hetznerClusterName, hetznerCluster); err != nil {
-		log.Info("HetznerCluster is not available yet")
-		return reconcile.Result{}, nil
-	}
-
-	log = log.WithValues("HetznerCluster", klog.KObj(hetznerCluster))
-	ctx = ctrl.LoggerInto(ctx, log)
-
-	// Create the scope.
-	secretManager := secretutil.NewSecretManager(log, r.Client, r.APIReader)
-	hcloudToken, _, err := getAndValidateHCloudToken(ctx, req.Namespace, hetznerCluster, secretManager)
-	if err != nil {
-		return hcloudTokenErrorResult(ctx, err, hcloudMachine, infrav1.InstanceReadyCondition, r.Client)
-	}
-
-	hcc := r.HCloudClientFactory.NewClient(hcloudToken)
-
-	remediationScope, err := scope.NewHCloudRemediationScope(ctx, scope.HCloudRemediationScopeParams{
-		Client:            r.Client,
-		Logger:            log,
-		Machine:           machine,
-		HCloudMachine:     hcloudMachine,
-		HetznerCluster:    hetznerCluster,
-		HCloudRemediation: hcloudRemediation,
-		HCloudClient:      hcc,
-	})
-	if err != nil {
-		return reconcile.Result{}, fmt.Errorf("failed to create scope: %w", err)
-	}
-
-	// Always close the scope when exiting this function so we can persist any HCloudRemediation changes.
-	defer func() {
-		// Always attempt to Patch the Remediation object and status after each reconciliation.
-		// Patch ObservedGeneration only if the reconciliation completed successfully
-		patchOpts := []patch.Option{}
-		patchOpts = append(patchOpts, patch.WithStatusObservedGeneration{})
-
-		if err := remediationScope.Close(ctx, patchOpts...); err != nil && reterr == nil {
-			reterr = err
-		}
-	}()
-
-	// Check whether rate limit has been reached and if so, then wait.
-	if wait := reconcileRateLimit(hcloudRemediation); wait {
-		return reconcile.Result{RequeueAfter: 30 * time.Second}, nil
-	}
-
-	if !hcloudRemediation.ObjectMeta.DeletionTimestamp.IsZero() {
-		// Nothing to do
-		return reconcile.Result{}, nil
-	}
-
-	return r.reconcileNormal(ctx, remediationScope)
-}
-
-func (r *HCloudRemediationReconciler) reconcileNormal(ctx context.Context, remediationScope *scope.HCloudRemediationScope) (reconcile.Result, error) {
-	remediationScope.Info("Reconciling HCloudRemediation")
-	hcloudRemediation := remediationScope.HCloudRemediation
-
-	// reconcile bare metal remediation
-	result, err := hcloudremediation.NewService(remediationScope).Reconcile(ctx)
-	if err != nil {
-		return result, fmt.Errorf("failed to reconcile server for HCloudRemediation %s/%s: %w",
-			hcloudRemediation.Namespace, hcloudRemediation.Name, err)
-	}
-
-	return result, nil
-}
-
-// SetupWithManager sets up the controller with the Manager.
-func (r *HCloudRemediationReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error {
-	return ctrl.NewControllerManagedBy(mgr).
-		For(&infrav1.HCloudRemediation{}).
-		WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue)).
-		Complete(r)
-}
diff --git a/controllers/hetznerbaremetalhost_controller.go b/controllers/hetznerbaremetalhost_controller.go
index 73492683..43d3e7a9 100644
--- a/controllers/hetznerbaremetalhost_controller.go
+++ b/controllers/hetznerbaremetalhost_controller.go
@@ -58,7 +58,7 @@ type HetznerBareMetalHostReconciler struct {
 //+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=hetznerbaremetalhosts/finalizers,verbs=update
 
 // Reconcile implements the reconcilement of HetznerBareMetalHost objects.
-func (r *HetznerBareMetalHostReconciler) Reconcile(ctx context.Context, req ctrl.Request) (res ctrl.Result, reterr error) {
+func (r *HetznerBareMetalHostReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) {
 	log := ctrl.LoggerFrom(ctx)
 
 	log.Info("Reconciling baremetal host", "name", req.Name)
@@ -89,10 +89,9 @@ func (r *HetznerBareMetalHostReconciler) Reconcile(ctx context.Context, req ctrl
 
 	// Certain cases need to be handled here and not later in the host state machine.
 	// If res != nil, then we should return, otherwise not.
-	res, err = r.reconcileSelectedStates(ctx, bmHost)
-	emptyResult := reconcile.Result{}
-	if res != emptyResult || err != nil {
-		return res, err
+	res, err := r.reconcileSelectedStates(ctx, bmHost)
+	if res != nil {
+		return *res, err
 	}
 
 	hetznerCluster := &infrav1.HetznerCluster{}
@@ -117,9 +116,10 @@ func (r *HetznerBareMetalHostReconciler) Reconcile(ctx context.Context, req ctrl
 
 	// Get secrets. Return when result != nil.
 	osSSHSecret, rescueSSHSecret, res, err := r.getSecrets(ctx, *secretManager, bmHost, hetznerCluster)
-	if err != nil || res != emptyResult {
-		return res, err
+	if res != nil {
+		return *res, err
 	}
+
 	// Create the scope.
 	hostScope, err := scope.NewBareMetalHostScope(ctx, scope.BareMetalHostScopeParams{
 		Logger:               log,
@@ -149,15 +149,18 @@ func (r *HetznerBareMetalHostReconciler) reconcile(
 	ctx context.Context,
 	hostScope *scope.BareMetalHostScope,
 ) (reconcile.Result, error) {
-	result, err := host.NewService(hostScope).Reconcile(ctx)
-	if err != nil {
-		return result, fmt.Errorf("failed to reconcile HetznerBareMetalHost %s/%s: %w",
-			hostScope.HetznerBareMetalHost.Namespace, hostScope.HetznerBareMetalHost.Name, err)
+	if result, brk, err := breakReconcile(host.NewService(hostScope).Reconcile(ctx)); brk {
+		return result, errors.Wrapf(
+			err,
+			"failed to reconcile HetznerBareMetalHost %s/%s",
+			hostScope.HetznerBareMetalHost.Namespace,
+			hostScope.HetznerBareMetalHost.Name,
+		)
 	}
-	return result, nil
+	return reconcile.Result{}, nil
 }
 
-func (r *HetznerBareMetalHostReconciler) reconcileSelectedStates(ctx context.Context, bmHost *infrav1.HetznerBareMetalHost) (res ctrl.Result, err error) {
+func (r *HetznerBareMetalHostReconciler) reconcileSelectedStates(ctx context.Context, bmHost *infrav1.HetznerBareMetalHost) (*ctrl.Result, error) {
 	log := ctrl.LoggerFrom(ctx)
 	switch bmHost.Spec.Status.ProvisioningState {
 	// Handle StateNone: check whether needs to be provisioned or deleted.
@@ -173,11 +176,11 @@ func (r *HetznerBareMetalHostReconciler) reconcileSelectedStates(ctx context.Con
 		if needsUpdate {
 			err := r.Update(ctx, bmHost)
 			if err != nil {
-				return res, errors.Wrap(err, "failed to add finalizer")
+				return nil, errors.Wrap(err, "failed to add finalizer")
 			}
 		}
 
-		return ctrl.Result{RequeueAfter: 10 * time.Second}, nil
+		return &ctrl.Result{RequeueAfter: 10 * time.Second}, nil
 
 		// Handle StateDeleting
 	case infrav1.StateDeleting:
@@ -185,17 +188,17 @@ func (r *HetznerBareMetalHostReconciler) reconcileSelectedStates(ctx context.Con
 
 		if !utils.StringInList(bmHost.Finalizers, infrav1.BareMetalHostFinalizer) {
 			log.Info("Ready to be deleted")
-			return res, nil
+			return nil, nil
 		}
 
 		bmHost.Finalizers = utils.FilterStringFromList(bmHost.Finalizers, infrav1.BareMetalHostFinalizer)
 		if err := r.Update(context.Background(), bmHost); err != nil {
-			return res, errors.Wrap(err, "failed to remove finalizer")
+			return nil, errors.Wrap(err, "failed to remove finalizer")
 		}
 		log.Info("Cleanup complete. Removed finalizer", "remaining", bmHost.Finalizers)
-		return res, nil
+		return nil, nil
 	}
-	return res, nil
+	return nil, nil
 }
 
 func (r *HetznerBareMetalHostReconciler) getSecrets(
@@ -206,10 +209,9 @@ func (r *HetznerBareMetalHostReconciler) getSecrets(
 ) (
 	osSSHSecret *corev1.Secret,
 	rescueSSHSecret *corev1.Secret,
-	res ctrl.Result,
+	res *ctrl.Result,
 	reterr error,
 ) {
-	emptyResult := reconcile.Result{}
 	if bmHost.Spec.Status.SSHSpec != nil {
 		var err error
 		osSSHSecretNamespacedName := types.NamespacedName{Namespace: bmHost.Namespace, Name: bmHost.Spec.Status.SSHSpec.SecretRef.Name}
@@ -218,14 +220,13 @@ func (r *HetznerBareMetalHostReconciler) getSecrets(
 			if apierrors.IsNotFound(err) {
 				bmHost.SetError(infrav1.PreparationError, infrav1.ErrorMessageMissingOSSSHSecret)
 
-				result, err := host.SaveHostAndReturn(ctx, r.Client, bmHost)
-				if result != emptyResult || err != nil {
-					return nil, nil, res, err
+				if res, brk, err := breakReconcile(host.SaveHostAndReturn(ctx, r.Client, bmHost)); brk {
+					return nil, nil, &res, err
 				}
 
-				return nil, nil, ctrl.Result{RequeueAfter: host.CalculateBackoff(bmHost.Spec.Status.ErrorCount)}, nil
+				return nil, nil, &ctrl.Result{RequeueAfter: host.CalculateBackoff(bmHost.Spec.Status.ErrorCount)}, nil
 			}
-			return nil, nil, res, errors.Wrap(err, "failed to get secret")
+			return nil, nil, nil, errors.Wrap(err, "failed to get secret")
 		}
 
 		rescueSSHSecretNamespacedName := types.NamespacedName{Namespace: bmHost.Namespace, Name: hetznerCluster.Spec.SSHKeys.RobotRescueSecretRef.Name}
@@ -234,17 +235,16 @@ func (r *HetznerBareMetalHostReconciler) getSecrets(
 			if apierrors.IsNotFound(err) {
 				bmHost.SetError(infrav1.PreparationError, infrav1.ErrorMessageMissingRescueSSHSecret)
 
-				result, err := host.SaveHostAndReturn(ctx, r.Client, bmHost)
-				if result != emptyResult || err != nil {
-					return nil, nil, result, err
+				if res, brk, err := breakReconcile(host.SaveHostAndReturn(ctx, r.Client, bmHost)); brk {
+					return nil, nil, &res, err
 				}
 
-				return nil, nil, ctrl.Result{RequeueAfter: host.CalculateBackoff(bmHost.Spec.Status.ErrorCount)}, nil
+				return nil, nil, &ctrl.Result{RequeueAfter: host.CalculateBackoff(bmHost.Spec.Status.ErrorCount)}, nil
 			}
-			return nil, nil, res, errors.Wrap(err, "failed to acquire secret")
+			return nil, nil, nil, errors.Wrap(err, "failed to acquire secret")
 		}
 	}
-	return osSSHSecret, rescueSSHSecret, res, nil
+	return osSSHSecret, rescueSSHSecret, nil, nil
 }
 
 func getAndValidateRobotCredentials(
@@ -296,10 +296,8 @@ func hetznerSecretErrorResult(
 	case *secretutil.ResolveSecretRefError:
 		bmHost.SetError(infrav1.PreparationError, infrav1.ErrorMessageMissingHetznerSecret)
 
-		result, err := host.SaveHostAndReturn(ctx, client, bmHost)
-		emptyResult := reconcile.Result{}
-		if result != emptyResult || err != nil {
-			return result, err
+		if res, brk, err := breakReconcile(host.SaveHostAndReturn(ctx, client, bmHost)); brk {
+			return res, err
 		}
 		backoff := host.CalculateBackoff(bmHost.Spec.Status.ErrorCount)
 		res = ctrl.Result{RequeueAfter: backoff}
@@ -307,7 +305,9 @@ func hetznerSecretErrorResult(
 	case *bmclient.CredentialsValidationError:
 		bmHost.SetError(infrav1.PreparationError, infrav1.ErrorMessageMissingOrInvalidSecretData)
 
-		res, err = host.SaveHostAndReturn(ctx, client, bmHost)
+		if res, brk, err := breakReconcile(host.SaveHostAndReturn(ctx, client, bmHost)); brk {
+			return res, err
+		}
 
 	default:
 		return ctrl.Result{}, errors.Wrap(err, "An unhandled failure occurred")
diff --git a/controllers/hetznerbaremetalmachine_controller.go b/controllers/hetznerbaremetalmachine_controller.go
index 76d0008d..a9c918dd 100644
--- a/controllers/hetznerbaremetalmachine_controller.go
+++ b/controllers/hetznerbaremetalmachine_controller.go
@@ -149,8 +149,7 @@ func (r *HetznerBareMetalMachineReconciler) Reconcile(ctx context.Context, req r
 func (r *HetznerBareMetalMachineReconciler) reconcileDelete(ctx context.Context, machineScope *scope.BareMetalMachineScope) (reconcile.Result, error) {
 	machineScope.Info("Reconciling HetznerBareMetalMachine delete")
 	// delete servers
-	result, err := baremetal.NewService(machineScope).Delete(ctx)
-	if err != nil {
+	if result, brk, err := breakReconcile(baremetal.NewService(machineScope).Delete(ctx)); brk {
 		var requeueError *scope.RequeueAfterError
 		if ok := errors.As(err, &requeueError); ok {
 			return reconcile.Result{Requeue: true, RequeueAfter: requeueError.GetRequeueAfter()}, nil
@@ -158,14 +157,11 @@ func (r *HetznerBareMetalMachineReconciler) reconcileDelete(ctx context.Context,
 		return result, fmt.Errorf("failed to delete servers for HetznerBareMetalMachine %s/%s: %w",
 			machineScope.BareMetalMachine.Namespace, machineScope.BareMetalMachine.Name, err)
 	}
-	emptyResult := reconcile.Result{}
-	if result != emptyResult {
-		return result, nil
-	}
+
 	// Machine is deleted so remove the finalizer.
 	controllerutil.RemoveFinalizer(machineScope.BareMetalMachine, infrav1.BareMetalMachineFinalizer)
 
-	return result, nil
+	return reconcile.Result{}, nil
 }
 
 func (r *HetznerBareMetalMachineReconciler) reconcileNormal(ctx context.Context, machineScope *scope.BareMetalMachineScope) (reconcile.Result, error) {
@@ -180,13 +176,12 @@ func (r *HetznerBareMetalMachineReconciler) reconcileNormal(ctx context.Context,
 	}
 
 	// reconcile server
-	result, err := baremetal.NewService(machineScope).Reconcile(ctx)
-	if err != nil {
+	if result, brk, err := breakReconcile(baremetal.NewService(machineScope).Reconcile(ctx)); brk {
 		return result, fmt.Errorf("failed to reconcile server for HetznerBareMetalMachine %s/%s: %w",
 			machineScope.BareMetalMachine.Namespace, machineScope.BareMetalMachine.Name, err)
 	}
 
-	return result, nil
+	return reconcile.Result{}, nil
 }
 
 // SetupWithManager sets up the controller with the Manager.
diff --git a/controllers/hetznerbaremetalremediation_controller.go b/controllers/hetznerbaremetalremediation_controller.go
index bf1fe382..4d3888da 100644
--- a/controllers/hetznerbaremetalremediation_controller.go
+++ b/controllers/hetznerbaremetalremediation_controller.go
@@ -157,13 +157,12 @@ func (r *HetznerBareMetalRemediationReconciler) reconcileNormal(ctx context.Cont
 	bareMetalRemediation := remediationScope.BareMetalRemediation
 
 	// reconcile bare metal remediation
-	result, err := remediation.NewService(remediationScope).Reconcile(ctx)
-	if err != nil {
+	if result, brk, err := breakReconcile(remediation.NewService(remediationScope).Reconcile(ctx)); brk {
 		return result, fmt.Errorf("failed to reconcile server for BareMetalRemediation %s/%s: %w",
 			bareMetalRemediation.Namespace, bareMetalRemediation.Name, err)
 	}
 
-	return result, nil
+	return reconcile.Result{}, nil
 }
 
 // SetupWithManager sets up the controller with the Manager.
diff --git a/controllers/utils.go b/controllers/utils.go
new file mode 100644
index 00000000..f1b4570d
--- /dev/null
+++ b/controllers/utils.go
@@ -0,0 +1,27 @@
+/*
+Copyright 2023 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package controllers
+
+import "sigs.k8s.io/controller-runtime/pkg/reconcile"
+
+func breakReconcile(ctrl *reconcile.Result, err error) (reconcile.Result, bool, error) {
+	c := reconcile.Result{}
+	if ctrl != nil {
+		c = *ctrl
+	}
+	return c, ctrl != nil || err != nil, err
+}
diff --git a/docs/reference/hcloud-remediation-template copy.md b/docs/reference/hcloud-remediation-template copy.md
deleted file mode 100644
index 4d4e9955..00000000
--- a/docs/reference/hcloud-remediation-template copy.md
+++ /dev/null
@@ -1,11 +0,0 @@
-## HCloudRemediationTemplate
-
-In ```HCloudRemediationTemplate``` you can define all important properties for ```HCloudRemediations```. With this remediation, you can define a custom method for the manner of how Machine Health Checks treat the unhealthy objects - `HCloudMachines` in this case. For more information about how to use remdiations, see [Advanced CAPH](/docs/topics/advanced-caph.md). ```HCloudRemediations``` are reconciled by the ```HCloudRemediationController```, which reconciles the remediatons and triggers the requested type of remediation on the relevant `HCloudMachine`.
-
-### Overview of HCloudRemediationTemplate.Spec
-| Key | Type | Default | Required | Description |
-|-----|-----|------|---------|-------------|
-| template.spec.strategy | object |  | yes | Remediation strategy to be applied |
-| template.spec.strategy.type | string | Reboot  | no | Type of the remediation strategy. At the moment, only "Reboot" is supported |
-| template.spec.strategy.retryLimit | int | 0 | no | Set maximum of remediation retries. Zero retries if not set. |
-| template.spec.strategy.timeout | string | | yes | Timeout of one remediation try. Should be of the form "10m", or "40s" |
diff --git a/docs/topics/advanced-caph.md b/docs/topics/advanced-caph.md
index 19094b77..fba797b2 100644
--- a/docs/topics/advanced-caph.md
+++ b/docs/topics/advanced-caph.md
@@ -26,14 +26,11 @@ We support multi-tenancy. You can start multiple clusters in one Hetzner project
 
 ## Machine Health Checks with Custom Remediation Template
 
-Cluster API allows to [configure Machine Health Checks](https://cluster-api.sigs.k8s.io/tasks/automated-machine-management/healthchecking.html) with custom remediation strategies. This is helpful for our bare metal servers. If the health checks find out that one server cannot be reached, the normal strategy would be to delete it. In that case it would need to be provisioned again. This takes, of course, longer for bare metal servers than for virtual cloud servers. Therefore, we want to try to avoid this with the help of our `HetznerBareMetalRemediationController` and `HCloudRemediationController`. Instead of deleting the object and deprovisioning it, we first try to reboot it and see whether this helps. If it solves the problem, we save a lot of time that is required for re-provisioning it.
+Cluster API allows to [configure Machine Health Checks](https://cluster-api.sigs.k8s.io/tasks/automated-machine-management/healthchecking.html) with custom remediation strategies. This is helpful for our bare metal servers. If the health checks find out that one server cannot be reached, the normal strategy would be to delete it. In that case it would need to be provisioned again. This takes, of course, longer for bare metal servers than for virtual cloud servers. Therefore, we want to try to avoid this with the help of our `HetznerBareMetalRemediationController`. Instead of deleting the object and deprovisioning it, we first try to reboot it and see whether this helps. If it solves the problem, we save a lot of time that is required for re-provisioning it.
 
-If the MHC are configured to be used with the `HetznerBareMetalRemediationTemplate` (also see the [reference of the object](/docs/reference/hetzner-bare-metal-remediation-template.md)) and `HCloudRemediationTemplate` (also see the [reference of the object](/docs/reference/hcloud-remediation-template.md)), then such an object is created every time the MHC finds an unhealthy machine. 
+If the MHC are configured to be used with the `HetznerBareMetalRemediationTemplate` (also see the [reference of the object](/docs/reference/hetzner-bare-metal-remediation-template.md)), then such an object is created every time the MHC finds an unhealthy machine. The controller that reconciles this object, then sets an annotation in the relevant `HetznerBareMetalHost` object that specifies the desired remediation strategy. At the moment, only "reboot" is supported.
 
-The `HetznerBareMetalRemediationController` reconciles this object, then sets an annotation in the relevant `HetznerBareMetalHost` object that specifies the desired remediation strategy. At the moment, only "reboot" is supported.
-The `HCloudRemediationController` reboots the HCloudMachine directly via HCloud API. For HCloud servers, there is no other strategy than "reboot" either.
-
-Here is an example of how to configure the Machine Health Check and `HetznerBareMetalRemediationTemplate`:
+Here is an example of how to configure the Machine Health Check and remediation template:
 
 ```yaml
 apiVersion: cluster.x-k8s.io/v1beta1
@@ -72,3 +69,6 @@ spec:
         timeout: 300s
 
 ```
+
+Please also refer to the [reference](/docs/reference/hetzner-bare-metal-remediation-template.md) for more details on how to configure the `HetznerBareMetalRemediationTemplate`
+
diff --git a/go.mod b/go.mod
index 2c91fc86..e5d690f6 100644
--- a/go.mod
+++ b/go.mod
@@ -6,11 +6,11 @@ replace sigs.k8s.io/cluster-api => sigs.k8s.io/cluster-api v1.3.5
 
 require (
 	github.com/blang/semver/v4 v4.0.0
-	github.com/go-logr/logr v1.2.4
+	github.com/go-logr/logr v1.2.3
 	github.com/go-logr/zapr v1.2.3
 	github.com/hetznercloud/hcloud-go v1.41.0
-	github.com/onsi/ginkgo/v2 v2.9.2
-	github.com/onsi/gomega v1.27.6
+	github.com/onsi/ginkgo/v2 v2.9.1
+	github.com/onsi/gomega v1.27.4
 	github.com/pkg/errors v0.9.1
 	github.com/stretchr/testify v1.8.2
 	github.com/syself/hrobot-go v0.2.4
@@ -65,7 +65,7 @@ require (
 	github.com/go-openapi/jsonpointer v0.19.5 // indirect
 	github.com/go-openapi/jsonreference v0.20.0 // indirect
 	github.com/go-openapi/swag v0.22.3 // indirect
-	github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
+	github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
 	github.com/gobuffalo/flect v0.3.0 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
diff --git a/go.sum b/go.sum
index 850ad877..8b2b9537 100644
--- a/go.sum
+++ b/go.sum
@@ -203,8 +203,8 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG
 github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
 github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
 github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
-github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
-github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
+github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
 github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A=
 github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4=
 github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
@@ -216,8 +216,8 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
 github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
 github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
-github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
 github.com/gobuffalo/flect v0.3.0 h1:erfPWM+K1rFNIQeRPdeEXxo8yFr/PO17lhRnS8FUrtk=
 github.com/gobuffalo/flect v0.3.0/go.mod h1:5pf3aGnsvqvCj50AVni7mJJF8ICxGZ8HomberC3pXLE=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -446,10 +446,10 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA
 github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
 github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
 github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
-github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU=
-github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts=
-github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
-github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
+github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk=
+github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo=
+github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E=
+github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ=
 github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
 github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM=
diff --git a/hack/tools/go.mod b/hack/tools/go.mod
index ada76172..4d79c43c 100644
--- a/hack/tools/go.mod
+++ b/hack/tools/go.mod
@@ -6,12 +6,12 @@ replace github.com/syself/cluster-api-provider-hetzner => ../../
 
 require (
 	github.com/drone/envsubst/v2 v2.0.0-20210730161058-179042472c46
-	github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572
+	github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0
 	github.com/google/pprof v0.0.0-20230323073829-e72429f035bd
 	github.com/joelanford/go-apidiff v0.6.0
 	github.com/nikolaydubina/go-binsize-treemap v0.2.0
 	github.com/nikolaydubina/go-cover-treemap v1.3.0
-	github.com/onsi/ginkgo/v2 v2.9.2
+	github.com/onsi/ginkgo/v2 v2.9.1
 	github.com/tilt-dev/ctlptl v0.8.17
 	gotest.tools/gotestsum v1.9.0
 	k8s.io/code-generator v0.25.4
@@ -130,7 +130,7 @@ require (
 	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
 	github.com/nikolaydubina/treemap v1.2.0 // indirect
 	github.com/olekukonko/tablewriter v0.0.5 // indirect
-	github.com/onsi/gomega v1.27.4 // indirect
+	github.com/onsi/gomega v1.27.3 // indirect
 	github.com/opencontainers/go-digest v1.0.0 // indirect
 	github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
 	github.com/pelletier/go-toml v1.9.5 // indirect
diff --git a/hack/tools/go.sum b/hack/tools/go.sum
index 4f5209ae..efba9552 100644
--- a/hack/tools/go.sum
+++ b/hack/tools/go.sum
@@ -489,8 +489,8 @@ github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+
 github.com/go-sql-driver/mysql v1.3.0 h1:pgwjLi/dvffoP9aabwkT3AKpXQM93QARkjFhDDqC1UE=
 github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
-github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
 github.com/gobuffalo/flect v0.3.0 h1:erfPWM+K1rFNIQeRPdeEXxo8yFr/PO17lhRnS8FUrtk=
 github.com/gobuffalo/flect v0.3.0/go.mod h1:5pf3aGnsvqvCj50AVni7mJJF8ICxGZ8HomberC3pXLE=
 github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
@@ -852,8 +852,8 @@ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
 github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
 github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
 github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
-github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU=
-github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts=
+github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk=
+github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo=
 github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
 github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
 github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@@ -861,8 +861,8 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
 github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
 github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
 github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
-github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E=
-github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ=
+github.com/onsi/gomega v1.27.3 h1:5VwIwnBY3vbBDOJrNtA4rVdiTZCsq9B5F12pvy1Drmk=
+github.com/onsi/gomega v1.27.3/go.mod h1:5vG284IBtfDAmDyrK+eGyZmUgUlmi+Wngqo557cZ6Gw=
 github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
 github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
 github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
diff --git a/hack/tools/vendor/github.com/onsi/ginkgo/v2/types/version.go b/hack/tools/vendor/github.com/onsi/ginkgo/v2/types/version.go
index 8e7f7404..0fb1054f 100644
--- a/hack/tools/vendor/github.com/onsi/ginkgo/v2/types/version.go
+++ b/hack/tools/vendor/github.com/onsi/ginkgo/v2/types/version.go
@@ -1,3 +1,3 @@
 package types
 
-const VERSION = "2.9.2"
+const VERSION = "2.9.1"
diff --git a/hack/tools/vendor/github.com/onsi/gomega/CHANGELOG.md b/hack/tools/vendor/github.com/onsi/gomega/CHANGELOG.md
index e702e3c9..b14ad91a 100644
--- a/hack/tools/vendor/github.com/onsi/gomega/CHANGELOG.md
+++ b/hack/tools/vendor/github.com/onsi/gomega/CHANGELOG.md
@@ -1,11 +1,3 @@
-## 1.27.4
-
-### Fixes
-- improve error formatting and remove duplication of error message in Eventually/Consistently [854f075]
-
-### Maintenance
-- Bump github.com/onsi/ginkgo/v2 from 2.9.0 to 2.9.1 (#650) [ccebd9b]
-
 ## 1.27.3
 
 ### Fixes
diff --git a/hack/tools/vendor/github.com/onsi/gomega/format/format.go b/hack/tools/vendor/github.com/onsi/gomega/format/format.go
index 56bdd053..3034c1a5 100644
--- a/hack/tools/vendor/github.com/onsi/gomega/format/format.go
+++ b/hack/tools/vendor/github.com/onsi/gomega/format/format.go
@@ -260,9 +260,9 @@ func Object(object interface{}, indentation uint) string {
 	value := reflect.ValueOf(object)
 	commonRepresentation := ""
 	if err, ok := object.(error); ok {
-		commonRepresentation += "\n" + IndentString(err.Error(), indentation) + "\n" + indent
+		commonRepresentation += "\n" + IndentString(err.Error(), indentation)
 	}
-	return fmt.Sprintf("%s<%s>: %s%s", indent, formatType(value), commonRepresentation, formatValue(value, indentation))
+	return fmt.Sprintf("%s<%s>: %s%s", indent, formatType(value), formatValue(value, indentation), commonRepresentation)
 }
 
 /*
diff --git a/hack/tools/vendor/github.com/onsi/gomega/gomega_dsl.go b/hack/tools/vendor/github.com/onsi/gomega/gomega_dsl.go
index e37251d8..015d784a 100644
--- a/hack/tools/vendor/github.com/onsi/gomega/gomega_dsl.go
+++ b/hack/tools/vendor/github.com/onsi/gomega/gomega_dsl.go
@@ -22,7 +22,7 @@ import (
 	"github.com/onsi/gomega/types"
 )
 
-const GOMEGA_VERSION = "1.27.4"
+const GOMEGA_VERSION = "1.27.3"
 
 const nilGomegaPanic = `You are trying to make an assertion, but haven't registered Gomega's fail handler.
 If you're using Ginkgo then you probably forgot to put your assertion in an It().
diff --git a/hack/tools/vendor/github.com/onsi/gomega/internal/async_assertion.go b/hack/tools/vendor/github.com/onsi/gomega/internal/async_assertion.go
index 1188b0bc..baa28d4a 100644
--- a/hack/tools/vendor/github.com/onsi/gomega/internal/async_assertion.go
+++ b/hack/tools/vendor/github.com/onsi/gomega/internal/async_assertion.go
@@ -412,7 +412,7 @@ func (assertion *AsyncAssertion) match(matcher types.GomegaMatcher, desiredMatch
 				message += format.Object(attachment.Object, 1)
 			}
 		} else {
-			message = preamble + "\n" + format.Object(err, 1)
+			message = preamble + "\n" + err.Error() + "\n" + format.Object(err, 1)
 		}
 		return message
 	}
diff --git a/hack/tools/vendor/modules.txt b/hack/tools/vendor/modules.txt
index 76512da4..452df088 100644
--- a/hack/tools/vendor/modules.txt
+++ b/hack/tools/vendor/modules.txt
@@ -309,7 +309,7 @@ github.com/go-openapi/jsonreference/internal
 # github.com/go-openapi/swag v0.22.3
 ## explicit; go 1.18
 github.com/go-openapi/swag
-# github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572
+# github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0
 ## explicit; go 1.13
 github.com/go-task/slim-sprig
 # github.com/gobuffalo/flect v0.3.0
@@ -546,7 +546,7 @@ github.com/nikolaydubina/treemap/render
 # github.com/olekukonko/tablewriter v0.0.5
 ## explicit; go 1.12
 github.com/olekukonko/tablewriter
-# github.com/onsi/ginkgo/v2 v2.9.2
+# github.com/onsi/ginkgo/v2 v2.9.1
 ## explicit; go 1.18
 github.com/onsi/ginkgo/v2/config
 github.com/onsi/ginkgo/v2/formatter
@@ -564,7 +564,7 @@ github.com/onsi/ginkgo/v2/internal/interrupt_handler
 github.com/onsi/ginkgo/v2/internal/parallel_support
 github.com/onsi/ginkgo/v2/reporters
 github.com/onsi/ginkgo/v2/types
-# github.com/onsi/gomega v1.27.4
+# github.com/onsi/gomega v1.27.3
 ## explicit; go 1.18
 github.com/onsi/gomega
 github.com/onsi/gomega/format
diff --git a/images/cache/Dockerfile b/images/cache/Dockerfile
index 60d40b59..15a06442 100644
--- a/images/cache/Dockerfile
+++ b/images/cache/Dockerfile
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 
-FROM docker.io/library/alpine:3.17.3@sha256:124c7d2707904eea7431fffe91522a01e5a861a624ee31d03372cc1d138a3126 as import-cache
+FROM docker.io/library/alpine:3.17.2@sha256:ff6bdca1701f3a8a67e328815ff2346b0e4067d32ec36b7992c1fdc001dc8517 as import-cache
 
 RUN --mount=type=bind,target=/host-tmp \
     --mount=type=cache,target=/root/.cache \
@@ -27,7 +27,7 @@ RUN --mount=type=bind,target=/host-tmp \
       tar xzf /host-tmp/go-pkg-cache.tar.gz --no-same-owner -C /go/pkg; \
     fi
 
-FROM docker.io/library/alpine:3.17.3@sha256:124c7d2707904eea7431fffe91522a01e5a861a624ee31d03372cc1d138a3126 as cache-creator
+FROM docker.io/library/alpine:3.17.2@sha256:ff6bdca1701f3a8a67e328815ff2346b0e4067d32ec36b7992c1fdc001dc8517 as cache-creator
 RUN --mount=type=cache,target=/root/.cache \
     --mount=type=cache,target=/go/pkg \
     tar czf /tmp/go-build-cache.tar.gz -C /root/.cache/go-build . ; \
diff --git a/main.go b/main.go
index 1aa689c8..fae6929e 100644
--- a/main.go
+++ b/main.go
@@ -169,16 +169,6 @@ func main() {
 		os.Exit(1)
 	}
 
-	if err = (&controllers.HCloudRemediationReconciler{
-		Client:              mgr.GetClient(),
-		APIReader:           mgr.GetAPIReader(),
-		HCloudClientFactory: hcloudClientFactory,
-		WatchFilterValue:    watchFilterValue,
-	}).SetupWithManager(ctx, mgr, controller.Options{}); err != nil {
-		setupLog.Error(err, "unable to create controller", "controller", "HCloudRemediation")
-		os.Exit(1)
-	}
-
 	setUpWebhookWithManager(mgr)
 
 	//+kubebuilder:scaffold:builder
@@ -241,12 +231,4 @@ func setUpWebhookWithManager(mgr ctrl.Manager) {
 		setupLog.Error(err, "unable to create webhook", "webhook", "HetznerBareMetalRemediationTemplate")
 		os.Exit(1)
 	}
-	if err := (&infrastructurev1beta1.HCloudRemediation{}).SetupWebhookWithManager(mgr); err != nil {
-		setupLog.Error(err, "unable to create webhook", "webhook", "HCloudRemediation")
-		os.Exit(1)
-	}
-	if err := (&infrastructurev1beta1.HCloudRemediationTemplate{}).SetupWebhookWithManager(mgr); err != nil {
-		setupLog.Error(err, "unable to create webhook", "webhook", "HCloudRemediationTemplate")
-		os.Exit(1)
-	}
 }
diff --git a/pkg/scope/hcloudremediation.go b/pkg/scope/hcloudremediation.go
deleted file mode 100644
index 8b387fa2..00000000
--- a/pkg/scope/hcloudremediation.go
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
-Copyright 2022 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package scope
-
-import (
-	"context"
-
-	"github.com/go-logr/logr"
-	"github.com/pkg/errors"
-	infrav1 "github.com/syself/cluster-api-provider-hetzner/api/v1beta1"
-	hcloudclient "github.com/syself/cluster-api-provider-hetzner/pkg/services/hcloud/client"
-	hcloudutil "github.com/syself/cluster-api-provider-hetzner/pkg/services/hcloud/util"
-	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
-	"sigs.k8s.io/cluster-api/util/patch"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-// HCloudRemediationScopeParams defines the input parameters used to create a new Scope.
-type HCloudRemediationScopeParams struct {
-	Logger            logr.Logger
-	Client            client.Client
-	HCloudClient      hcloudclient.Client
-	Machine           *clusterv1.Machine
-	HCloudMachine     *infrav1.HCloudMachine
-	HetznerCluster    *infrav1.HetznerCluster
-	HCloudRemediation *infrav1.HCloudRemediation
-}
-
-// NewHCloudRemediationScope creates a new Scope from the supplied parameters.
-// This is meant to be called for each reconcile iteration.
-func NewHCloudRemediationScope(ctx context.Context, params HCloudRemediationScopeParams) (*HCloudRemediationScope, error) {
-	if params.HCloudRemediation == nil {
-		return nil, errors.New("failed to generate new scope from nil HCloudRemediation")
-	}
-	if params.Client == nil {
-		return nil, errors.New("failed to generate new scope from nil client")
-	}
-	if params.HCloudClient == nil {
-		return nil, errors.New("failed to generate new scope from nil HCloudClient")
-	}
-	if params.Machine == nil {
-		return nil, errors.New("failed to generate new scope from nil Machine")
-	}
-	if params.HCloudMachine == nil {
-		return nil, errors.New("failed to generate new scope from nil HCloudMachine")
-	}
-
-	emptyLogger := logr.Logger{}
-	if params.Logger == emptyLogger {
-		return nil, errors.New("failed to generate new scope from nil Logger")
-	}
-
-	patchHelper, err := patch.NewHelper(params.HCloudRemediation, params.Client)
-	if err != nil {
-		return nil, errors.Wrap(err, "failed to init patch helper")
-	}
-
-	machinePatchHelper, err := patch.NewHelper(params.Machine, params.Client)
-	if err != nil {
-		return nil, errors.Wrap(err, "failed to init machine patch helper")
-	}
-
-	return &HCloudRemediationScope{
-		Logger:             params.Logger,
-		Client:             params.Client,
-		HCloudClient:       params.HCloudClient,
-		patchHelper:        patchHelper,
-		machinePatchHelper: machinePatchHelper,
-		Machine:            params.Machine,
-		HCloudMachine:      params.HCloudMachine,
-		HCloudRemediation:  params.HCloudRemediation,
-	}, nil
-}
-
-// HCloudRemediationScope defines the basic context for an actuator to operate upon.
-type HCloudRemediationScope struct {
-	logr.Logger
-	Client             client.Client
-	patchHelper        *patch.Helper
-	machinePatchHelper *patch.Helper
-	HCloudClient       hcloudclient.Client
-	Machine            *clusterv1.Machine
-	HCloudMachine      *infrav1.HCloudMachine
-	HCloudRemediation  *infrav1.HCloudRemediation
-}
-
-// Close closes the current scope persisting the cluster configuration and status.
-func (m *HCloudRemediationScope) Close(ctx context.Context, opts ...patch.Option) error {
-	return m.patchHelper.Patch(ctx, m.HCloudRemediation, opts...)
-}
-
-// Name returns the HCloudMachine name.
-func (m *HCloudRemediationScope) Name() string {
-	return m.HCloudRemediation.Name
-}
-
-// Namespace returns the namespace name.
-func (m *HCloudRemediationScope) Namespace() string {
-	return m.HCloudRemediation.Namespace
-}
-
-// ServerIDFromProviderID returns the namespace name.
-func (m *HCloudRemediationScope) ServerIDFromProviderID() (int, error) {
-	return hcloudutil.ServerIDFromProviderID(m.HCloudMachine.Spec.ProviderID)
-}
-
-// PatchObject persists the remediation spec and status.
-func (m *HCloudRemediationScope) PatchObject(ctx context.Context, opts ...patch.Option) error {
-	return m.patchHelper.Patch(ctx, m.HCloudRemediation, opts...)
-}
-
-// PatchMachine persists the machine spec and status.
-func (m *HCloudRemediationScope) PatchMachine(ctx context.Context, opts ...patch.Option) error {
-	return m.machinePatchHelper.Patch(ctx, m.Machine, opts...)
-}
diff --git a/pkg/services/baremetal/baremetal/baremetal.go b/pkg/services/baremetal/baremetal/baremetal.go
index 8e433ce5..ad1475cf 100644
--- a/pkg/services/baremetal/baremetal/baremetal.go
+++ b/pkg/services/baremetal/baremetal/baremetal.go
@@ -74,7 +74,7 @@ func NewService(scope *scope.BareMetalMachineScope) *Service {
 }
 
 // Reconcile implements reconcilement of HetznerBareMetalMachines.
-func (s *Service) Reconcile(ctx context.Context) (res reconcile.Result, err error) {
+func (s *Service) Reconcile(ctx context.Context) (_ *reconcile.Result, err error) {
 	s.scope.Info("Reconciling bare metal machine")
 
 	// Make sure bootstrap data is available and populated. If not, return, we
@@ -87,7 +87,7 @@ func (s *Service) Reconcile(ctx context.Context) (res reconcile.Result, err erro
 			clusterv1.ConditionSeverityInfo,
 			"bootstrap not ready yet",
 		)
-		return res, nil
+		return nil, nil
 	}
 
 	conditions.MarkTrue(
@@ -105,36 +105,36 @@ func (s *Service) Reconcile(ctx context.Context) (res reconcile.Result, err erro
 
 	// update the machine
 	if err := s.update(ctx); err != nil {
-		return checkForRequeueError(err, "failed to update machine")
+		return nil, fmt.Errorf("failed to update machine: %w", err)
 	}
 
 	// set providerID if necessary
 	if err := s.setProviderID(ctx); err != nil {
-		return res, fmt.Errorf("failed to set providerID: %w", err)
+		return nil, fmt.Errorf("failed to set providerID: %w", err)
 	}
 
 	// set machine ready
 	s.scope.BareMetalMachine.Status.Ready = true
 	conditions.MarkTrue(s.scope.BareMetalMachine, infrav1.InstanceReadyCondition)
 
-	return res, nil
+	return nil, nil
 }
 
 // Delete implements delete method of bare metal machine.
-func (s *Service) Delete(ctx context.Context) (res reconcile.Result, err error) {
+func (s *Service) Delete(ctx context.Context) (_ *reconcile.Result, err error) {
 	s.scope.Info("Deleting bare metal machine")
 
 	// get host - ignore if not found
 	host, helper, err := s.getAssociatedHost(ctx)
 	if err != nil && !apierrors.IsNotFound(err) {
-		return res, fmt.Errorf("failed to get associated host: %w", err)
+		return nil, fmt.Errorf("failed to get associated host: %w", err)
 	}
 
 	if host != nil && host.Spec.ConsumerRef != nil {
 		// remove control plane as load balancer target
 		if s.scope.IsControlPlane() && s.scope.HetznerCluster.Spec.ControlPlaneLoadBalancer.Enabled {
 			if err := s.removeAttachedServerOfLoadBalancer(ctx, host); err != nil {
-				return res, fmt.Errorf("failed to delete attached server of load balancer: %w", err)
+				return nil, fmt.Errorf("failed to delete attached server of load balancer: %w", err)
 			}
 		}
 
@@ -145,23 +145,23 @@ func (s *Service) Delete(ctx context.Context) (res reconcile.Result, err error)
 			// remove the ownerRef to this host, even if the consumerRef references another machine
 			host.OwnerReferences = s.removeOwnerRef(host.OwnerReferences)
 
-			return res, nil
+			return nil, nil
 		}
 
 		if removeMachineSpecsFromHost(host) {
 			// Patch the host object. If the error is NotFound, do not return the error.
 			if err := analyzePatchError(helper.Patch(ctx, host), true); err != nil {
-				return checkForRequeueError(err, "failed to patch host")
+				return nil, fmt.Errorf("failed to patch host: %w", err)
 			}
 
 			s.scope.Info("Patched BaremetalHost while deprovisioning, requeuing")
-			return reconcile.Result{Requeue: true}, nil
+			return nil, &scope.RequeueAfterError{}
 		}
 
 		// check if deprovisioning is done
 		if host.Spec.Status.ProvisioningState != infrav1.StateNone {
 			s.scope.Info("Deprovisioning BaremetalHost, requeuing", "provisioning state", host.Spec.Status.ProvisioningState)
-			return reconcile.Result{RequeueAfter: requeueAfter}, nil
+			return nil, &scope.RequeueAfterError{RequeueAfter: requeueAfter}
 		}
 
 		// deprovisiong is done - remove all references of host
@@ -177,7 +177,7 @@ func (s *Service) Delete(ctx context.Context) (res reconcile.Result, err error)
 
 		// patch host object
 		if err := analyzePatchError(helper.Patch(ctx, host), true); err != nil {
-			return checkForRequeueError(err, "failed to patch host")
+			return nil, fmt.Errorf("failed to patch host: %w", err)
 		}
 	}
 
@@ -189,7 +189,7 @@ func (s *Service) Delete(ctx context.Context) (res reconcile.Result, err error)
 		"HetznerBareMetalMachine with name %s deleted",
 		s.scope.Name(),
 	)
-	return res, nil
+	return nil, nil
 }
 
 // update updates a machine and is invoked by the Machine Controller.
@@ -814,16 +814,16 @@ func splitHostKey(key string) (namespace, name string) {
 	return parts[0], parts[1]
 }
 
-func checkForRequeueError(err error, errMessage string) (res reconcile.Result, reterr error) {
+func checkForRequeueError(err error, errMessage string) (*reconcile.Result, error) {
 	if err == nil {
-		return res, nil
+		return nil, nil
 	}
 	var requeueError *scope.RequeueAfterError
 	if ok := errors.As(err, &requeueError); ok {
-		return reconcile.Result{Requeue: true, RequeueAfter: requeueError.GetRequeueAfter()}, nil
+		return &reconcile.Result{Requeue: true, RequeueAfter: requeueError.GetRequeueAfter()}, nil
 	}
 
-	return res, fmt.Errorf("%s: %w", errMessage, err)
+	return nil, fmt.Errorf("%s: %w", errMessage, err)
 }
 
 func providerIDFromServerID(serverID int) string {
diff --git a/pkg/services/baremetal/host/host.go b/pkg/services/baremetal/host/host.go
index f8fdfc16..31cebb3d 100644
--- a/pkg/services/baremetal/host/host.go
+++ b/pkg/services/baremetal/host/host.go
@@ -68,7 +68,7 @@ func NewService(scope *scope.BareMetalHostScope) *Service {
 }
 
 // Reconcile implements reconcilement of HetznerBareMetalHosts.
-func (s *Service) Reconcile(ctx context.Context) (result ctrl.Result, err error) {
+func (s *Service) Reconcile(ctx context.Context) (_ *ctrl.Result, err error) {
 	s.scope.Info("Reconciling baremetal host", "name", s.scope.HetznerBareMetalHost.Name)
 
 	initialState := s.scope.HetznerBareMetalHost.Spec.Status.ProvisioningState
@@ -79,9 +79,9 @@ func (s *Service) Reconcile(ctx context.Context) (result ctrl.Result, err error)
 
 	// reconcile state
 	actResult := hostStateMachine.ReconcileState(ctx)
-	result, err = actResult.Result()
+	result, err := actResult.Result()
 	if err != nil {
-		return ctrl.Result{Requeue: true}, fmt.Errorf("action %q failed: %w", initialState, err)
+		return &ctrl.Result{Requeue: true}, fmt.Errorf("action %q failed: %w", initialState, err)
 	}
 
 	// save host if it changed during reconciliation
@@ -89,7 +89,7 @@ func (s *Service) Reconcile(ctx context.Context) (result ctrl.Result, err error)
 		return SaveHostAndReturn(ctx, s.scope.Client, s.scope.HetznerBareMetalHost)
 	}
 
-	return result, nil
+	return &result, nil
 }
 
 func (s *Service) recordActionFailure(errorType infrav1.ErrorType, errorMessage string) actionFailed {
@@ -99,17 +99,17 @@ func (s *Service) recordActionFailure(errorType infrav1.ErrorType, errorMessage
 }
 
 // SaveHostAndReturn saves host object, updates LastUpdated in host status and returns the reconcile Result.
-func SaveHostAndReturn(ctx context.Context, client client.Client, host *infrav1.HetznerBareMetalHost) (res reconcile.Result, err error) {
+func SaveHostAndReturn(ctx context.Context, client client.Client, host *infrav1.HetznerBareMetalHost) (*reconcile.Result, error) {
 	t := metav1.Now()
 	host.Spec.Status.LastUpdated = &t
 
 	if err := client.Update(ctx, host); err != nil {
 		if apierrors.IsConflict(err) {
-			return reconcile.Result{Requeue: true}, nil
+			return &reconcile.Result{Requeue: true}, nil
 		}
-		return res, fmt.Errorf("failed to update host object: %w", err)
+		return nil, fmt.Errorf("failed to update host object: %w", err)
 	}
-	return res, nil
+	return nil, nil
 }
 
 func (s *Service) getSSHKeysAndUpdateStatus() (osSSHSecret *corev1.Secret, rescueSSHSecret *corev1.Secret, err error) {
@@ -266,9 +266,6 @@ func (s *Service) actionPreparing() actionResult {
 }
 
 func (s *Service) ensureSSHKey(sshSecretRef infrav1.SSHSecretRef, sshSecret *corev1.Secret) (infrav1.SSHKey, actionResult) {
-	if sshSecret == nil {
-		return infrav1.SSHKey{}, actionError{err: fmt.Errorf("ssh secret is nil")}
-	}
 	hetznerSSHKeys, err := s.scope.RobotClient.ListSSHKeys()
 	if err != nil {
 		if models.IsError(err, models.ErrorCodeRateLimitExceeded) {
diff --git a/pkg/services/baremetal/remediation/remediation.go b/pkg/services/baremetal/remediation/remediation.go
index 34f94c89..65a224fc 100644
--- a/pkg/services/baremetal/remediation/remediation.go
+++ b/pkg/services/baremetal/remediation/remediation.go
@@ -50,7 +50,7 @@ func NewService(scope *scope.BareMetalRemediationScope) *Service {
 }
 
 // Reconcile implements reconcilement of Hetzner bare metal remediation.
-func (s *Service) Reconcile(ctx context.Context) (res ctrl.Result, err error) {
+func (s *Service) Reconcile(ctx context.Context) (_ *ctrl.Result, err error) {
 	log := ctrl.LoggerFrom(ctx)
 
 	log.Info("Reconciling baremetal remediation", "name", s.scope.BareMetalRemediation.Name)
@@ -59,7 +59,7 @@ func (s *Service) Reconcile(ctx context.Context) (res ctrl.Result, err error) {
 	host, helper, err := s.getUnhealthyHost(ctx)
 	if err != nil {
 		s.scope.Error(err, "unable to find a host for unhealthy machine")
-		return res, errors.Wrapf(err, "unable to find a host for unhealthy machine")
+		return nil, errors.Wrapf(err, "unable to find a host for unhealthy machine")
 	}
 
 	// If host is not in state provisioned, then remediate immediately
@@ -67,18 +67,18 @@ func (s *Service) Reconcile(ctx context.Context) (res ctrl.Result, err error) {
 		log.Info("Deleting host without remediation", "provisioningState", host.Spec.Status.ProvisioningState)
 		if err := s.setOwnerRemediatedConditionNew(ctx); err != nil {
 			s.scope.Error(err, "error setting cluster api conditions")
-			return res, errors.Wrapf(err, "error setting cluster api conditions")
+			return nil, errors.Wrapf(err, "error setting cluster api conditions")
 		}
 	}
 
 	remediationType := s.scope.BareMetalRemediation.Spec.Strategy.Type
 
-	if remediationType != infrav1.RemediationTypeReboot {
+	if remediationType != infrav1.RebootRemediationStrategy {
 		s.scope.Info("unsupported remediation strategy")
-		return res, nil
+		return nil, nil
 	}
 
-	if remediationType == infrav1.RemediationTypeReboot {
+	if remediationType == infrav1.RebootRemediationStrategy {
 		// If no phase set, default to running
 		if s.scope.BareMetalRemediation.Status.Phase == "" {
 			s.scope.BareMetalRemediation.Status.Phase = infrav1.PhaseRunning
@@ -92,17 +92,17 @@ func (s *Service) Reconcile(ctx context.Context) (res ctrl.Result, err error) {
 		default:
 		}
 	}
-	return res, nil
+	return nil, nil
 }
 
-func (s *Service) handlePhaseRunning(ctx context.Context, host *infrav1.HetznerBareMetalHost, helper *patch.Helper) (res ctrl.Result, err error) {
+func (s *Service) handlePhaseRunning(ctx context.Context, host *infrav1.HetznerBareMetalHost, helper *patch.Helper) (*ctrl.Result, error) {
 	// host is not rebooted yet
 	if s.scope.BareMetalRemediation.Status.LastRemediated == nil {
 		s.scope.Info("Rebooting the host")
 		err := s.setRebootAnnotation(ctx, host, helper)
 		if err != nil {
 			s.scope.Error(err, "error setting reboot annotation")
-			return res, errors.Wrap(err, "error setting reboot annotation")
+			return nil, errors.Wrap(err, "error setting reboot annotation")
 		}
 		now := metav1.Now()
 		s.scope.BareMetalRemediation.Status.LastRemediated = &now
@@ -117,7 +117,7 @@ func (s *Service) handlePhaseRunning(ctx context.Context, host *infrav1.HetznerB
 			err := s.setRebootAnnotation(ctx, host, helper)
 			if err != nil {
 				s.scope.Error(err, "error setting reboot annotation")
-				return res, errors.Wrapf(err, "error setting reboot annotation")
+				return nil, errors.Wrapf(err, "error setting reboot annotation")
 			}
 			now := metav1.Now()
 			s.scope.BareMetalRemediation.Status.LastRemediated = &now
@@ -126,15 +126,15 @@ func (s *Service) handlePhaseRunning(ctx context.Context, host *infrav1.HetznerB
 
 		if nextRemediation > 0 {
 			// Not yet time to remediate, requeue
-			return ctrl.Result{RequeueAfter: nextRemediation}, nil
+			return &ctrl.Result{RequeueAfter: nextRemediation}, nil
 		}
 	} else {
 		s.scope.BareMetalRemediation.Status.Phase = infrav1.PhaseWaiting
 	}
-	return res, nil
+	return nil, nil
 }
 
-func (s *Service) handlePhaseWaiting(ctx context.Context) (res ctrl.Result, err error) {
+func (s *Service) handlePhaseWaiting(ctx context.Context) (*ctrl.Result, error) {
 	okToStop, nextCheck := s.timeToRemediate(s.scope.BareMetalRemediation.Spec.Strategy.Timeout.Duration)
 
 	if okToStop {
@@ -146,15 +146,15 @@ func (s *Service) handlePhaseWaiting(ctx context.Context) (res ctrl.Result, err
 		err := s.setOwnerRemediatedConditionNew(ctx)
 		if err != nil {
 			s.scope.Error(err, "error setting cluster api conditions")
-			return res, errors.Wrapf(err, "error setting cluster api conditions")
+			return nil, errors.Wrapf(err, "error setting cluster api conditions")
 		}
 	}
 
 	if nextCheck > 0 {
 		// Not yet time to stop remediation, requeue
-		return ctrl.Result{RequeueAfter: nextCheck}, nil
+		return &ctrl.Result{RequeueAfter: nextCheck}, nil
 	}
-	return res, nil
+	return nil, nil
 }
 
 func (s *Service) getUnhealthyHost(ctx context.Context) (*infrav1.HetznerBareMetalHost, *patch.Helper, error) {
diff --git a/pkg/services/hcloud/client/client.go b/pkg/services/hcloud/client/client.go
index 82add046..4c1d8806 100644
--- a/pkg/services/hcloud/client/client.go
+++ b/pkg/services/hcloud/client/client.go
@@ -45,12 +45,10 @@ type Client interface {
 	CreateServer(context.Context, hcloud.ServerCreateOpts) (hcloud.ServerCreateResult, error)
 	AttachServerToNetwork(context.Context, *hcloud.Server, hcloud.ServerAttachToNetworkOpts) (*hcloud.Action, error)
 	ListServers(context.Context, hcloud.ServerListOpts) ([]*hcloud.Server, error)
-	GetServer(context.Context, int) (*hcloud.Server, error)
 	DeleteServer(context.Context, *hcloud.Server) error
 	ListServerTypes(context.Context) ([]*hcloud.ServerType, error)
 	PowerOnServer(context.Context, *hcloud.Server) (*hcloud.Action, error)
 	ShutdownServer(context.Context, *hcloud.Server) (*hcloud.Action, error)
-	RebootServer(context.Context, *hcloud.Server) (*hcloud.Action, error)
 	CreateNetwork(context.Context, hcloud.NetworkCreateOpts) (*hcloud.Network, error)
 	ListNetworks(context.Context, hcloud.NetworkListOpts) ([]*hcloud.Network, error)
 	DeleteNetwork(context.Context, *hcloud.Network) error
@@ -173,11 +171,6 @@ func (c *realClient) ListServers(ctx context.Context, opts hcloud.ServerListOpts
 	return c.client.Server.AllWithOpts(ctx, opts)
 }
 
-func (c *realClient) GetServer(ctx context.Context, id int) (*hcloud.Server, error) {
-	res, _, err := c.client.Server.GetByID(ctx, id)
-	return res, err
-}
-
 func (c *realClient) ListServerTypes(ctx context.Context) ([]*hcloud.ServerType, error) {
 	return c.client.ServerType.All(ctx)
 }
@@ -187,11 +180,6 @@ func (c *realClient) ShutdownServer(ctx context.Context, server *hcloud.Server)
 	return res, err
 }
 
-func (c *realClient) RebootServer(ctx context.Context, server *hcloud.Server) (*hcloud.Action, error) {
-	res, _, err := c.client.Server.Reboot(ctx, server)
-	return res, err
-}
-
 func (c *realClient) PowerOnServer(ctx context.Context, server *hcloud.Server) (*hcloud.Action, error) {
 	res, _, err := c.client.Server.Poweron(ctx, server)
 	return res, err
diff --git a/pkg/services/hcloud/client/fake/hcloud_client.go b/pkg/services/hcloud/client/fake/hcloud_client.go
index 78ec2163..284aa219 100644
--- a/pkg/services/hcloud/client/fake/hcloud_client.go
+++ b/pkg/services/hcloud/client/fake/hcloud_client.go
@@ -464,10 +464,6 @@ func (c *cacheHCloudClient) ListServers(ctx context.Context, opts hcloud.ServerL
 	return servers, nil
 }
 
-func (c *cacheHCloudClient) GetServer(ctx context.Context, id int) (*hcloud.Server, error) {
-	return c.serverCache.idMap[id], nil
-}
-
 func (c *cacheHCloudClient) ShutdownServer(ctx context.Context, server *hcloud.Server) (*hcloud.Action, error) {
 	if _, found := c.serverCache.idMap[server.ID]; !found {
 		return nil, hcloud.Error{Code: hcloud.ErrorCodeNotFound, Message: "not found"}
@@ -476,10 +472,6 @@ func (c *cacheHCloudClient) ShutdownServer(ctx context.Context, server *hcloud.S
 	return &hcloud.Action{}, nil
 }
 
-func (c *cacheHCloudClient) RebootServer(ctx context.Context, server *hcloud.Server) (*hcloud.Action, error) {
-	return nil, nil
-}
-
 func (c *cacheHCloudClient) PowerOnServer(ctx context.Context, server *hcloud.Server) (*hcloud.Action, error) {
 	if _, found := c.serverCache.idMap[server.ID]; !found {
 		return nil, hcloud.Error{Code: hcloud.ErrorCodeNotFound, Message: "not found"}
diff --git a/pkg/services/hcloud/machinetemplate/machinetemplate.go b/pkg/services/hcloud/machinetemplate/machinetemplate.go
index 415a4c51..07620a1b 100644
--- a/pkg/services/hcloud/machinetemplate/machinetemplate.go
+++ b/pkg/services/hcloud/machinetemplate/machinetemplate.go
@@ -28,6 +28,7 @@ import (
 	corev1 "k8s.io/api/core/v1"
 	"sigs.k8s.io/cluster-api/util/conditions"
 	"sigs.k8s.io/cluster-api/util/record"
+	ctrl "sigs.k8s.io/controller-runtime"
 )
 
 // Service defines struct with HCloudMachineTemplate scope to reconcile HCloud machine templates.
@@ -43,14 +44,14 @@ func NewService(scope *scope.HCloudMachineTemplateScope) *Service {
 }
 
 // Reconcile implements reconcilement of HCloud machines.
-func (s *Service) Reconcile(ctx context.Context) error {
+func (s *Service) Reconcile(ctx context.Context) (_ *ctrl.Result, err error) {
 	capacity, err := s.getCapacity(ctx)
 	if err != nil {
-		return errors.Wrap(err, "failed to get capacity")
+		return nil, errors.Wrap(err, "failed to get capacity")
 	}
 
 	s.scope.HCloudMachineTemplate.Status.Capacity = capacity
-	return nil
+	return nil, nil
 }
 
 func (s *Service) getCapacity(ctx context.Context) (corev1.ResourceList, error) {
diff --git a/pkg/services/hcloud/remediation/remediation.go b/pkg/services/hcloud/remediation/remediation.go
deleted file mode 100644
index ce92f0fb..00000000
--- a/pkg/services/hcloud/remediation/remediation.go
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
-Copyright 2022 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-// Package remediation implements functions to manage the lifecycle of hcloud remediation.
-package remediation
-
-import (
-	"context"
-	"fmt"
-	"time"
-
-	"github.com/hetznercloud/hcloud-go/hcloud"
-	infrav1 "github.com/syself/cluster-api-provider-hetzner/api/v1beta1"
-	"github.com/syself/cluster-api-provider-hetzner/pkg/scope"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	capi "sigs.k8s.io/cluster-api/api/v1beta1"
-	"sigs.k8s.io/cluster-api/util/conditions"
-	"sigs.k8s.io/cluster-api/util/record"
-	ctrl "sigs.k8s.io/controller-runtime"
-)
-
-// Service defines struct with machine scope to reconcile HCloudRemediation.
-type Service struct {
-	scope *scope.HCloudRemediationScope
-}
-
-// NewService outs a new service with machine scope.
-func NewService(scope *scope.HCloudRemediationScope) *Service {
-	return &Service{
-		scope: scope,
-	}
-}
-
-// Reconcile implements reconcilement of HCloudRemediation.
-func (s *Service) Reconcile(ctx context.Context) (res ctrl.Result, err error) {
-	s.scope.Info("Reconciling hcloud remediation", "name", s.scope.HCloudRemediation.Name)
-
-	server, err := s.findServer(ctx)
-	if err != nil {
-		return res, fmt.Errorf("failed to find the server of unhealthy machine: %w", err)
-	}
-
-	remediationType := s.scope.HCloudRemediation.Spec.Strategy.Type
-
-	if remediationType != infrav1.RemediationTypeReboot {
-		s.scope.Info("unsupported remediation strategy")
-		record.Warnf(s.scope.HCloudRemediation, "UnsupportedRemdiationStrategy", "remediation strategy %q is unsupported", remediationType)
-		return res, nil
-	}
-
-	if remediationType == infrav1.RemediationTypeReboot {
-		// If no phase set, default to running
-		if s.scope.HCloudRemediation.Status.Phase == "" {
-			s.scope.HCloudRemediation.Status.Phase = infrav1.PhaseRunning
-		}
-
-		switch s.scope.HCloudRemediation.Status.Phase {
-		case infrav1.PhaseRunning:
-			return s.handlePhaseRunning(ctx, server)
-		case infrav1.PhaseWaiting:
-			return s.handlePhaseWaiting(ctx)
-		default:
-		}
-	}
-	return res, nil
-}
-
-func (s *Service) handlePhaseRunning(ctx context.Context, server *hcloud.Server) (res ctrl.Result, err error) {
-	// server is not rebooted yet
-	if s.scope.HCloudRemediation.Status.LastRemediated == nil {
-		s.scope.Info("Rebooting the server")
-
-		if err := s.rebootServer(ctx, server); err != nil {
-			return res, fmt.Errorf("failed to reboot server: %w", err)
-		}
-
-		now := metav1.Now()
-		s.scope.HCloudRemediation.Status.LastRemediated = &now
-		s.scope.HCloudRemediation.Status.RetryCount++
-	}
-
-	retryLimit := s.scope.HCloudRemediation.Spec.Strategy.RetryLimit
-	retryCount := s.scope.HCloudRemediation.Status.RetryCount
-
-	if retryLimit > 0 && retryLimit > retryCount {
-		okToRemediate, nextRemediation := s.timeToRemediate()
-
-		if okToRemediate {
-			s.scope.Info("Rebooting the server")
-
-			if err := s.rebootServer(ctx, server); err != nil {
-				return res, fmt.Errorf("failed to reboot server: %w", err)
-			}
-
-			now := metav1.Now()
-			s.scope.HCloudRemediation.Status.LastRemediated = &now
-			s.scope.HCloudRemediation.Status.RetryCount++
-		}
-
-		if nextRemediation > 0 {
-			// Not yet time to remediate, requeue
-			return ctrl.Result{RequeueAfter: nextRemediation}, nil
-		}
-	} else {
-		s.scope.HCloudRemediation.Status.Phase = infrav1.PhaseWaiting
-	}
-	return res, nil
-}
-
-func (s *Service) handlePhaseWaiting(ctx context.Context) (res ctrl.Result, err error) {
-	okToStop, nextCheck := s.timeToRemediate()
-
-	if okToStop {
-		s.scope.HCloudRemediation.Status.Phase = infrav1.PhaseDeleting
-		// When machine is still unhealthy after remediation, setting of OwnerRemediatedCondition
-		// moves control to CAPI machine controller. The owning controller will do
-		// preflight checks and handles the Machine deletion
-
-		if err := s.setOwnerRemediatedCondition(ctx); err != nil {
-			return res, fmt.Errorf("failed to set conditions on CAPI machine: %w", err)
-		}
-	}
-
-	if nextCheck > 0 {
-		// Not yet time to stop remediation, requeue
-		return ctrl.Result{RequeueAfter: nextCheck}, nil
-	}
-	return res, nil
-}
-
-func (s *Service) findServer(ctx context.Context) (*hcloud.Server, error) {
-	serverID, err := s.scope.ServerIDFromProviderID()
-	if err != nil {
-		return nil, fmt.Errorf("failed to get serverID from providerID: %w", err)
-	}
-
-	server, err := s.scope.HCloudClient.GetServer(ctx, serverID)
-	if err != nil {
-		if hcloud.IsError(err, hcloud.ErrorCodeRateLimitExceeded) {
-			conditions.MarkTrue(s.scope.HCloudRemediation, infrav1.RateLimitExceeded)
-			record.Event(s.scope.HCloudRemediation,
-				"RateLimitExceeded",
-				"exceeded rate limit with calling hcloud function GetServer",
-			)
-		}
-		return nil, fmt.Errorf("failed to get server: %w", err)
-	}
-
-	return server, nil
-}
-
-func (s *Service) rebootServer(ctx context.Context, server *hcloud.Server) error {
-	s.scope.Info("Rebooting server", "server", server.ID)
-	if _, err := s.scope.HCloudClient.RebootServer(ctx, server); err != nil {
-		if hcloud.IsError(err, hcloud.ErrorCodeRateLimitExceeded) {
-			conditions.MarkTrue(s.scope.HCloudRemediation, infrav1.RateLimitExceeded)
-			record.Event(s.scope.HCloudRemediation,
-				"RateLimitExceeded",
-				"exceeded rate limit with calling hcloud function RebootServer",
-			)
-		}
-		return fmt.Errorf("failed to reboot server %v: %w", server.ID, err)
-	}
-	return nil
-}
-
-// timeToRemediate checks if it is time to execute a next remediation step
-// and returns seconds to next remediation time.
-func (s *Service) timeToRemediate() (bool, time.Duration) {
-	now := time.Now()
-	timeout := s.scope.HCloudRemediation.Spec.Strategy.Timeout.Duration
-	lastRemediated := s.scope.HCloudRemediation.Status.LastRemediated
-
-	// status is not updated yet
-	if lastRemediated == nil {
-		return false, timeout
-	}
-
-	if lastRemediated.Add(timeout).Before(now) {
-		return true, time.Duration(0)
-	}
-
-	timeElapsedSinceLastRemediation := now.Sub(lastRemediated.Time)
-	nextRemediation := timeout - timeElapsedSinceLastRemediation + time.Second
-	return false, nextRemediation
-}
-
-// setOwnerRemediatedCondition sets MachineOwnerRemediatedCondition on CAPI machine object
-// that have failed a healthcheck.
-func (s *Service) setOwnerRemediatedCondition(ctx context.Context) error {
-	conditions.MarkFalse(
-		s.scope.Machine,
-		capi.MachineOwnerRemediatedCondition,
-		capi.WaitingForRemediationReason,
-		capi.ConditionSeverityWarning,
-		"",
-	)
-	if err := s.scope.PatchMachine(ctx); err != nil {
-		return fmt.Errorf("failed to patch machine: %w", err)
-	}
-	return nil
-}
diff --git a/pkg/services/hcloud/server/server.go b/pkg/services/hcloud/server/server.go
index f1dfd664..9ab83ef2 100644
--- a/pkg/services/hcloud/server/server.go
+++ b/pkg/services/hcloud/server/server.go
@@ -53,11 +53,11 @@ func NewService(scope *scope.MachineScope) *Service {
 }
 
 // Reconcile implements reconcilement of HCloud machines.
-func (s *Service) Reconcile(ctx context.Context) (res reconcile.Result, err error) {
+func (s *Service) Reconcile(ctx context.Context) (_ *reconcile.Result, err error) {
 	// detect failure domain
 	failureDomain, err := s.scope.GetFailureDomain()
 	if err != nil {
-		return res, fmt.Errorf("failed to get failure domain: %w", err)
+		return nil, fmt.Errorf("failed to get failure domain: %w", err)
 	}
 
 	// set in status of machine
@@ -72,7 +72,7 @@ func (s *Service) Reconcile(ctx context.Context) (res reconcile.Result, err erro
 			clusterv1.ConditionSeverityInfo,
 			"bootstrap not ready yet",
 		)
-		return reconcile.Result{RequeueAfter: 10 * time.Second}, nil
+		return &reconcile.Result{RequeueAfter: 10 * time.Second}, nil
 	}
 
 	conditions.MarkTrue(s.scope.HCloudMachine, infrav1.InstanceBootstrapReadyCondition)
@@ -80,14 +80,14 @@ func (s *Service) Reconcile(ctx context.Context) (res reconcile.Result, err erro
 	// try to find an existing server
 	server, err := s.findServer(ctx)
 	if err != nil {
-		return res, fmt.Errorf("failed to get server: %w", err)
+		return nil, fmt.Errorf("failed to get server: %w", err)
 	}
 
 	// if no server is found we have to create one
 	if server == nil {
 		server, err = s.createServer(ctx)
 		if err != nil {
-			return res, fmt.Errorf("failed to create server: %w", err)
+			return nil, fmt.Errorf("failed to create server: %w", err)
 		}
 
 		record.Eventf(s.scope.HCloudMachine, "SuccessfulCreate", "Created new server with id %d", server.ID)
@@ -106,17 +106,17 @@ func (s *Service) Reconcile(ctx context.Context) (res reconcile.Result, err erro
 		// If we don't return here, the condition InstanceReady would get marked as true in this
 		// case. However, if the server is stuck and does not power on, we should not mark the
 		// condition InstanceReady as true to be able to remediate the server after a timeout.
-		return reconcile.Result{RequeueAfter: 10 * time.Second}, nil
+		return &reconcile.Result{RequeueAfter: 10 * time.Second}, nil
 	case hcloud.ServerStatusRunning: // Do nothing
 	default:
 		s.scope.SetReady(false)
 		s.scope.V(1).Info("server not in running state", "server", server.Name, "status", server.Status)
-		return reconcile.Result{RequeueAfter: 2 * time.Second}, nil
+		return &reconcile.Result{RequeueAfter: 2 * time.Second}, nil
 	}
 
 	// check whether server is attached to the network
 	if err := s.reconcileNetworkAttachment(ctx, server); err != nil {
-		return res, fmt.Errorf("failed to reconcile network attachement: %w", err)
+		return nil, fmt.Errorf("failed to reconcile network attachement: %w", err)
 	}
 
 	providerID := providerIDFromServerID(server.ID)
@@ -125,39 +125,39 @@ func (s *Service) Reconcile(ctx context.Context) (res reconcile.Result, err erro
 		s.scope.SetProviderID(providerID)
 		s.scope.SetReady(true)
 		conditions.MarkTrue(s.scope.HCloudMachine, infrav1.InstanceReadyCondition)
-		return res, nil
+		return nil, nil
 	}
 
 	// all control planes have to be attached to the load balancer if it exists
 	if err := s.reconcileLoadBalancerAttachment(ctx, server); err != nil {
-		return res, fmt.Errorf("failed to reconcile load balancer attachement: %w", err)
+		return nil, fmt.Errorf("failed to reconcile load balancer attachement: %w", err)
 	}
 
 	s.scope.SetProviderID(providerID)
 	s.scope.SetReady(true)
 	conditions.MarkTrue(s.scope.HCloudMachine, infrav1.InstanceReadyCondition)
 
-	return res, nil
+	return nil, nil
 }
 
 // Delete implements delete method of server.
-func (s *Service) Delete(ctx context.Context) (res reconcile.Result, err error) {
+func (s *Service) Delete(ctx context.Context) (_ *reconcile.Result, err error) {
 	// find current server
 	server, err := s.findServer(ctx)
 	if err != nil {
-		return res, fmt.Errorf("failed to find server: %w", err)
+		return nil, fmt.Errorf("failed to find server: %w", err)
 	}
 
 	// if no server has been found, then nothing can be deleted
 	if server == nil {
 		s.scope.V(1).Info("Unable to locate HCloud server by ID or tags")
 		record.Warnf(s.scope.HCloudMachine, "NoInstanceFound", "Unable to find matching HCloud server for %s", s.scope.Name())
-		return res, nil
+		return nil, nil
 	}
 
 	if s.scope.IsControlPlane() && s.scope.HetznerCluster.Spec.ControlPlaneLoadBalancer.Enabled {
 		if err := s.deleteServerOfLoadBalancer(ctx, server); err != nil {
-			return res, fmt.Errorf("failed to delete attached server of loadbalancer: %w", err)
+			return nil, fmt.Errorf("failed to delete attached server of loadbalancer: %w", err)
 		}
 	}
 
@@ -169,7 +169,7 @@ func (s *Service) Delete(ctx context.Context) (res reconcile.Result, err error)
 		return s.handleDeleteServerStatusOff(ctx, server)
 	}
 
-	return reconcile.Result{RequeueAfter: 5 * time.Second}, nil
+	return &reconcile.Result{RequeueAfter: 5 * time.Second}, nil
 }
 
 func (s *Service) reconcileNetworkAttachment(ctx context.Context, server *hcloud.Server) error {
@@ -452,7 +452,7 @@ func (s *Service) getServerImage(ctx context.Context) (*hcloud.Image, error) {
 	return images[0], nil
 }
 
-func (s *Service) handleServerStatusOff(ctx context.Context, server *hcloud.Server) (res reconcile.Result, err error) {
+func (s *Service) handleServerStatusOff(ctx context.Context, server *hcloud.Server) (*reconcile.Result, error) {
 	// Check if server is in ServerStatusOff and turn it on. This is to avoid a bug of Hetzner where
 	// sometimes machines are created and not turned on
 
@@ -470,12 +470,12 @@ func (s *Service) handleServerStatusOff(ctx context.Context, server *hcloud.Serv
 						"exceeded rate limit with calling hcloud function PowerOnServer",
 					)
 				}
-				return res, fmt.Errorf("failed to power on server: %w", err)
+				return nil, fmt.Errorf("failed to power on server: %w", err)
 			}
 		} else {
 			// Timed out. Set failure reason
 			s.scope.SetError("reached timeout of waiting for machines that are switched off", capierrors.CreateMachineError)
-			return res, nil
+			return nil, nil
 		}
 	} else {
 		// No condition set yet. Try to power server on.
@@ -487,7 +487,7 @@ func (s *Service) handleServerStatusOff(ctx context.Context, server *hcloud.Serv
 					"exceeded rate limit with calling hcloud function PowerOnServer",
 				)
 			}
-			return res, fmt.Errorf("failed to power on server: %w", err)
+			return nil, fmt.Errorf("failed to power on server: %w", err)
 		}
 		conditions.MarkFalse(
 			s.scope.HCloudMachine,
@@ -499,10 +499,10 @@ func (s *Service) handleServerStatusOff(ctx context.Context, server *hcloud.Serv
 	}
 
 	// Try again in 30 sec.
-	return reconcile.Result{RequeueAfter: 30 * time.Second}, nil
+	return &reconcile.Result{RequeueAfter: 30 * time.Second}, nil
 }
 
-func (s *Service) handleDeleteServerStatusRunning(ctx context.Context, server *hcloud.Server) (res reconcile.Result, err error) {
+func (s *Service) handleDeleteServerStatusRunning(ctx context.Context, server *hcloud.Server) (*reconcile.Result, error) {
 	// Check if the server has been tried to shut down already and if so,
 	// whether the time of the last condition change + maxWaitTime is already in the past.
 	// With one of these two conditions true, delete server immediately. Otherwise, shut it down and requeue.
@@ -518,14 +518,14 @@ func (s *Service) handleDeleteServerStatusRunning(ctx context.Context, server *h
 					"exceeded rate limit with calling hcloud function ShutdownServer",
 				)
 			}
-			return res, fmt.Errorf("failed to shutdown server: %w", err)
+			return nil, fmt.Errorf("failed to shutdown server: %w", err)
 		}
 		conditions.MarkFalse(s.scope.HCloudMachine,
 			infrav1.InstanceReadyCondition,
 			infrav1.InstanceTerminatedReason,
 			clusterv1.ConditionSeverityInfo,
 			"Instance has been shut down")
-		return reconcile.Result{RequeueAfter: 30 * time.Second}, nil
+		return &reconcile.Result{RequeueAfter: 30 * time.Second}, nil
 	}
 	if err := s.scope.HCloudClient.DeleteServer(ctx, server); err != nil {
 		if hcloud.IsError(err, hcloud.ErrorCodeRateLimitExceeded) {
@@ -536,7 +536,7 @@ func (s *Service) handleDeleteServerStatusRunning(ctx context.Context, server *h
 			)
 		}
 		record.Warnf(s.scope.HCloudMachine, "FailedDeleteHCloudServer", "Failed to delete HCloud server %s", s.scope.Name())
-		return res, fmt.Errorf("failed to delete server: %w", err)
+		return nil, fmt.Errorf("failed to delete server: %w", err)
 	}
 
 	record.Eventf(
@@ -545,10 +545,10 @@ func (s *Service) handleDeleteServerStatusRunning(ctx context.Context, server *h
 		"HCloud server %s deleted",
 		s.scope.Name(),
 	)
-	return res, nil
+	return nil, nil
 }
 
-func (s *Service) handleDeleteServerStatusOff(ctx context.Context, server *hcloud.Server) (res reconcile.Result, err error) {
+func (s *Service) handleDeleteServerStatusOff(ctx context.Context, server *hcloud.Server) (*reconcile.Result, error) {
 	if err := s.scope.HCloudClient.DeleteServer(ctx, server); err != nil {
 		if hcloud.IsError(err, hcloud.ErrorCodeRateLimitExceeded) {
 			conditions.MarkTrue(s.scope.HCloudMachine, infrav1.RateLimitExceeded)
@@ -558,7 +558,7 @@ func (s *Service) handleDeleteServerStatusOff(ctx context.Context, server *hclou
 			)
 		}
 		record.Warnf(s.scope.HCloudMachine, "FailedDeleteHCloudServer", "Failed to delete HCloud server %s", s.scope.Name())
-		return res, fmt.Errorf("failed to delete server: %w", err)
+		return nil, fmt.Errorf("failed to delete server: %w", err)
 	}
 
 	record.Eventf(
@@ -567,7 +567,7 @@ func (s *Service) handleDeleteServerStatusOff(ctx context.Context, server *hclou
 		"HCloud server %s deleted",
 		s.scope.Name(),
 	)
-	return res, nil
+	return nil, nil
 }
 
 func (s *Service) deleteServerOfLoadBalancer(ctx context.Context, server *hcloud.Server) error {
diff --git a/pkg/services/hcloud/util/utils.go b/pkg/services/hcloud/util/utils.go
deleted file mode 100644
index 5c73f524..00000000
--- a/pkg/services/hcloud/util/utils.go
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-// Package hcloudutil contains utility functions for hcloud servers.
-package hcloudutil
-
-import (
-	"fmt"
-	"strconv"
-	"strings"
-)
-
-const providerIDPrefix = "hcloud://"
-
-var (
-	// ErrInvalidProviderID indicates that the providerID is invalid.
-	ErrInvalidProviderID = fmt.Errorf("invalid providerID")
-	// ErrNilProviderID indicates that the providerID is nil.
-	ErrNilProviderID = fmt.Errorf("nil providerID")
-)
-
-// ProviderIDFromServerID returns the providerID of a hcloud server from a serverID.
-func ProviderIDFromServerID(serverID int) string {
-	return fmt.Sprintf("%s%v", providerIDPrefix, serverID)
-}
-
-// ServerIDFromProviderID returns the serverID from a providerID.
-func ServerIDFromProviderID(providerID *string) (int, error) {
-	if providerID == nil {
-		return 0, ErrNilProviderID
-	}
-	stringParts := strings.Split(*providerID, "://")
-	if len(stringParts) != 2 || stringParts[0] == "" || stringParts[1] == "" {
-		return 0, ErrInvalidProviderID
-	}
-	idString := stringParts[1]
-	id, err := strconv.Atoi(idString)
-	if err != nil {
-		return 0, fmt.Errorf("failed to convert serverID to int - %w: %w", ErrInvalidProviderID, err)
-	}
-
-	return id, nil
-}
diff --git a/vendor/github.com/go-logr/logr/.golangci.yaml b/vendor/github.com/go-logr/logr/.golangci.yaml
index 0cffafa7..94ff801d 100644
--- a/vendor/github.com/go-logr/logr/.golangci.yaml
+++ b/vendor/github.com/go-logr/logr/.golangci.yaml
@@ -6,6 +6,7 @@ linters:
   disable-all: true
   enable:
     - asciicheck
+    - deadcode
     - errcheck
     - forcetypeassert
     - gocritic
@@ -17,8 +18,10 @@ linters:
     - misspell
     - revive
     - staticcheck
+    - structcheck
     - typecheck
     - unused
+    - varcheck
 
 issues:
   exclude-use-default: false
diff --git a/vendor/github.com/go-logr/logr/discard.go b/vendor/github.com/go-logr/logr/discard.go
index 99fe8be9..9d92a38f 100644
--- a/vendor/github.com/go-logr/logr/discard.go
+++ b/vendor/github.com/go-logr/logr/discard.go
@@ -20,5 +20,35 @@ package logr
 // used whenever the caller is not interested in the logs.  Logger instances
 // produced by this function always compare as equal.
 func Discard() Logger {
-	return New(nil)
+	return Logger{
+		level: 0,
+		sink:  discardLogSink{},
+	}
+}
+
+// discardLogSink is a LogSink that discards all messages.
+type discardLogSink struct{}
+
+// Verify that it actually implements the interface
+var _ LogSink = discardLogSink{}
+
+func (l discardLogSink) Init(RuntimeInfo) {
+}
+
+func (l discardLogSink) Enabled(int) bool {
+	return false
+}
+
+func (l discardLogSink) Info(int, string, ...interface{}) {
+}
+
+func (l discardLogSink) Error(error, string, ...interface{}) {
+}
+
+func (l discardLogSink) WithValues(...interface{}) LogSink {
+	return l
+}
+
+func (l discardLogSink) WithName(string) LogSink {
+	return l
 }
diff --git a/vendor/github.com/go-logr/logr/funcr/funcr.go b/vendor/github.com/go-logr/logr/funcr/funcr.go
index e52f0cd0..7accdb0c 100644
--- a/vendor/github.com/go-logr/logr/funcr/funcr.go
+++ b/vendor/github.com/go-logr/logr/funcr/funcr.go
@@ -21,13 +21,13 @@ limitations under the License.
 // github.com/go-logr/logr.LogSink with output through an arbitrary
 // "write" function.  See New and NewJSON for details.
 //
-// # Custom LogSinks
+// Custom LogSinks
 //
 // For users who need more control, a funcr.Formatter can be embedded inside
 // your own custom LogSink implementation. This is useful when the LogSink
 // needs to implement additional methods, for example.
 //
-// # Formatting
+// Formatting
 //
 // This will respect logr.Marshaler, fmt.Stringer, and error interfaces for
 // values which are being logged.  When rendering a struct, funcr will use Go's
@@ -37,7 +37,6 @@ package funcr
 import (
 	"bytes"
 	"encoding"
-	"encoding/json"
 	"fmt"
 	"path/filepath"
 	"reflect"
@@ -218,7 +217,7 @@ func newFormatter(opts Options, outfmt outputFormat) Formatter {
 		prefix:       "",
 		values:       nil,
 		depth:        0,
-		opts:         &opts,
+		opts:         opts,
 	}
 	return f
 }
@@ -232,7 +231,7 @@ type Formatter struct {
 	values       []interface{}
 	valuesStr    string
 	depth        int
-	opts         *Options
+	opts         Options
 }
 
 // outputFormat indicates which outputFormat to use.
@@ -448,7 +447,6 @@ func (f Formatter) prettyWithFlags(value interface{}, flags uint32, depth int) s
 		if flags&flagRawStruct == 0 {
 			buf.WriteByte('{')
 		}
-		printComma := false // testing i>0 is not enough because of JSON omitted fields
 		for i := 0; i < t.NumField(); i++ {
 			fld := t.Field(i)
 			if fld.PkgPath != "" {
@@ -480,10 +478,9 @@ func (f Formatter) prettyWithFlags(value interface{}, flags uint32, depth int) s
 			if omitempty && isEmpty(v.Field(i)) {
 				continue
 			}
-			if printComma {
+			if i > 0 {
 				buf.WriteByte(',')
 			}
-			printComma = true // if we got here, we are rendering a field
 			if fld.Anonymous && fld.Type.Kind() == reflect.Struct && name == "" {
 				buf.WriteString(f.prettyWithFlags(v.Field(i).Interface(), flags|flagRawStruct, depth+1))
 				continue
@@ -503,20 +500,6 @@ func (f Formatter) prettyWithFlags(value interface{}, flags uint32, depth int) s
 		}
 		return buf.String()
 	case reflect.Slice, reflect.Array:
-		// If this is outputing as JSON make sure this isn't really a json.RawMessage.
-		// If so just emit "as-is" and don't pretty it as that will just print
-		// it as [X,Y,Z,...] which isn't terribly useful vs the string form you really want.
-		if f.outputFormat == outputJSON {
-			if rm, ok := value.(json.RawMessage); ok {
-				// If it's empty make sure we emit an empty value as the array style would below.
-				if len(rm) > 0 {
-					buf.Write(rm)
-				} else {
-					buf.WriteString("null")
-				}
-				return buf.String()
-			}
-		}
 		buf.WriteByte('[')
 		for i := 0; i < v.Len(); i++ {
 			if i > 0 {
diff --git a/vendor/github.com/go-logr/logr/logr.go b/vendor/github.com/go-logr/logr/logr.go
index e027aea3..c3b56b3d 100644
--- a/vendor/github.com/go-logr/logr/logr.go
+++ b/vendor/github.com/go-logr/logr/logr.go
@@ -21,7 +21,7 @@ limitations under the License.
 // to back that API.  Packages in the Go ecosystem can depend on this package,
 // while callers can implement logging with whatever backend is appropriate.
 //
-// # Usage
+// Usage
 //
 // Logging is done using a Logger instance.  Logger is a concrete type with
 // methods, which defers the actual logging to a LogSink interface.  The main
@@ -30,20 +30,16 @@ limitations under the License.
 // "structured logging".
 //
 // With Go's standard log package, we might write:
-//
-//	log.Printf("setting target value %s", targetValue)
+//   log.Printf("setting target value %s", targetValue)
 //
 // With logr's structured logging, we'd write:
-//
-//	logger.Info("setting target", "value", targetValue)
+//   logger.Info("setting target", "value", targetValue)
 //
 // Errors are much the same.  Instead of:
-//
-//	log.Printf("failed to open the pod bay door for user %s: %v", user, err)
+//   log.Printf("failed to open the pod bay door for user %s: %v", user, err)
 //
 // We'd write:
-//
-//	logger.Error(err, "failed to open the pod bay door", "user", user)
+//   logger.Error(err, "failed to open the pod bay door", "user", user)
 //
 // Info() and Error() are very similar, but they are separate methods so that
 // LogSink implementations can choose to do things like attach additional
@@ -51,7 +47,7 @@ limitations under the License.
 // always logged, regardless of the current verbosity.  If there is no error
 // instance available, passing nil is valid.
 //
-// # Verbosity
+// Verbosity
 //
 // Often we want to log information only when the application in "verbose
 // mode".  To write log lines that are more verbose, Logger has a V() method.
@@ -62,22 +58,20 @@ limitations under the License.
 // Error messages do not have a verbosity level and are always logged.
 //
 // Where we might have written:
-//
-//	if flVerbose >= 2 {
-//	    log.Printf("an unusual thing happened")
-//	}
+//   if flVerbose >= 2 {
+//       log.Printf("an unusual thing happened")
+//   }
 //
 // We can write:
+//   logger.V(2).Info("an unusual thing happened")
 //
-//	logger.V(2).Info("an unusual thing happened")
-//
-// # Logger Names
+// Logger Names
 //
 // Logger instances can have name strings so that all messages logged through
 // that instance have additional context.  For example, you might want to add
 // a subsystem name:
 //
-//	logger.WithName("compactor").Info("started", "time", time.Now())
+//   logger.WithName("compactor").Info("started", "time", time.Now())
 //
 // The WithName() method returns a new Logger, which can be passed to
 // constructors or other functions for further use.  Repeated use of WithName()
@@ -88,27 +82,25 @@ limitations under the License.
 // joining operation (e.g. whitespace, commas, periods, slashes, brackets,
 // quotes, etc).
 //
-// # Saved Values
+// Saved Values
 //
 // Logger instances can store any number of key/value pairs, which will be
 // logged alongside all messages logged through that instance.  For example,
 // you might want to create a Logger instance per managed object:
 //
 // With the standard log package, we might write:
-//
-//	log.Printf("decided to set field foo to value %q for object %s/%s",
-//	    targetValue, object.Namespace, object.Name)
+//   log.Printf("decided to set field foo to value %q for object %s/%s",
+//       targetValue, object.Namespace, object.Name)
 //
 // With logr we'd write:
+//   // Elsewhere: set up the logger to log the object name.
+//   obj.logger = mainLogger.WithValues(
+//       "name", obj.name, "namespace", obj.namespace)
 //
-//	// Elsewhere: set up the logger to log the object name.
-//	obj.logger = mainLogger.WithValues(
-//	    "name", obj.name, "namespace", obj.namespace)
-//
-//	// later on...
-//	obj.logger.Info("setting foo", "value", targetValue)
+//   // later on...
+//   obj.logger.Info("setting foo", "value", targetValue)
 //
-// # Best Practices
+// Best Practices
 //
 // Logger has very few hard rules, with the goal that LogSink implementations
 // might have a lot of freedom to differentiate.  There are, however, some
@@ -132,15 +124,15 @@ limitations under the License.
 // around. For cases where passing a logger is optional, a pointer to Logger
 // should be used.
 //
-// # Key Naming Conventions
+// Key Naming Conventions
 //
 // Keys are not strictly required to conform to any specification or regex, but
 // it is recommended that they:
-//   - be human-readable and meaningful (not auto-generated or simple ordinals)
-//   - be constant (not dependent on input data)
-//   - contain only printable characters
-//   - not contain whitespace or punctuation
-//   - use lower case for simple keys and lowerCamelCase for more complex ones
+//   * be human-readable and meaningful (not auto-generated or simple ordinals)
+//   * be constant (not dependent on input data)
+//   * contain only printable characters
+//   * not contain whitespace or punctuation
+//   * use lower case for simple keys and lowerCamelCase for more complex ones
 //
 // These guidelines help ensure that log data is processed properly regardless
 // of the log implementation.  For example, log implementations will try to
@@ -149,54 +141,51 @@ limitations under the License.
 // While users are generally free to use key names of their choice, it's
 // generally best to avoid using the following keys, as they're frequently used
 // by implementations:
-//   - "caller": the calling information (file/line) of a particular log line
-//   - "error": the underlying error value in the `Error` method
-//   - "level": the log level
-//   - "logger": the name of the associated logger
-//   - "msg": the log message
-//   - "stacktrace": the stack trace associated with a particular log line or
-//     error (often from the `Error` message)
-//   - "ts": the timestamp for a log line
+//   * "caller": the calling information (file/line) of a particular log line
+//   * "error": the underlying error value in the `Error` method
+//   * "level": the log level
+//   * "logger": the name of the associated logger
+//   * "msg": the log message
+//   * "stacktrace": the stack trace associated with a particular log line or
+//                   error (often from the `Error` message)
+//   * "ts": the timestamp for a log line
 //
 // Implementations are encouraged to make use of these keys to represent the
 // above concepts, when necessary (for example, in a pure-JSON output form, it
 // would be necessary to represent at least message and timestamp as ordinary
 // named values).
 //
-// # Break Glass
+// Break Glass
 //
 // Implementations may choose to give callers access to the underlying
 // logging implementation.  The recommended pattern for this is:
-//
-//	// Underlier exposes access to the underlying logging implementation.
-//	// Since callers only have a logr.Logger, they have to know which
-//	// implementation is in use, so this interface is less of an abstraction
-//	// and more of way to test type conversion.
-//	type Underlier interface {
-//	    GetUnderlying() <underlying-type>
-//	}
+//   // Underlier exposes access to the underlying logging implementation.
+//   // Since callers only have a logr.Logger, they have to know which
+//   // implementation is in use, so this interface is less of an abstraction
+//   // and more of way to test type conversion.
+//   type Underlier interface {
+//       GetUnderlying() <underlying-type>
+//   }
 //
 // Logger grants access to the sink to enable type assertions like this:
-//
-//	func DoSomethingWithImpl(log logr.Logger) {
-//	    if underlier, ok := log.GetSink().(impl.Underlier); ok {
-//	       implLogger := underlier.GetUnderlying()
-//	       ...
-//	    }
-//	}
+//   func DoSomethingWithImpl(log logr.Logger) {
+//       if underlier, ok := log.GetSink()(impl.Underlier) {
+//          implLogger := underlier.GetUnderlying()
+//          ...
+//       }
+//   }
 //
 // Custom `With*` functions can be implemented by copying the complete
 // Logger struct and replacing the sink in the copy:
-//
-//	// WithFooBar changes the foobar parameter in the log sink and returns a
-//	// new logger with that modified sink.  It does nothing for loggers where
-//	// the sink doesn't support that parameter.
-//	func WithFoobar(log logr.Logger, foobar int) logr.Logger {
-//	   if foobarLogSink, ok := log.GetSink().(FoobarSink); ok {
-//	      log = log.WithSink(foobarLogSink.WithFooBar(foobar))
-//	   }
-//	   return log
-//	}
+//   // WithFooBar changes the foobar parameter in the log sink and returns a
+//   // new logger with that modified sink.  It does nothing for loggers where
+//   // the sink doesn't support that parameter.
+//   func WithFoobar(log logr.Logger, foobar int) logr.Logger {
+//      if foobarLogSink, ok := log.GetSink()(FoobarSink); ok {
+//         log = log.WithSink(foobarLogSink.WithFooBar(foobar))
+//      }
+//      return log
+//   }
 //
 // Don't use New to construct a new Logger with a LogSink retrieved from an
 // existing Logger. Source code attribution might not work correctly and
@@ -212,14 +201,11 @@ import (
 )
 
 // New returns a new Logger instance.  This is primarily used by libraries
-// implementing LogSink, rather than end users.  Passing a nil sink will create
-// a Logger which discards all log lines.
+// implementing LogSink, rather than end users.
 func New(sink LogSink) Logger {
 	logger := Logger{}
 	logger.setSink(sink)
-	if sink != nil {
-		sink.Init(runtimeInfo)
-	}
+	sink.Init(runtimeInfo)
 	return logger
 }
 
@@ -258,7 +244,7 @@ type Logger struct {
 // Enabled tests whether this Logger is enabled.  For example, commandline
 // flags might be used to set the logging verbosity and disable some info logs.
 func (l Logger) Enabled() bool {
-	return l.sink != nil && l.sink.Enabled(l.level)
+	return l.sink.Enabled(l.level)
 }
 
 // Info logs a non-error message with the given key/value pairs as context.
@@ -268,9 +254,6 @@ func (l Logger) Enabled() bool {
 // information.  The key/value pairs must alternate string keys and arbitrary
 // values.
 func (l Logger) Info(msg string, keysAndValues ...interface{}) {
-	if l.sink == nil {
-		return
-	}
 	if l.Enabled() {
 		if withHelper, ok := l.sink.(CallStackHelperLogSink); ok {
 			withHelper.GetCallStackHelper()()
@@ -290,9 +273,6 @@ func (l Logger) Info(msg string, keysAndValues ...interface{}) {
 // triggered this log line, if present. The err parameter is optional
 // and nil may be passed instead of an error instance.
 func (l Logger) Error(err error, msg string, keysAndValues ...interface{}) {
-	if l.sink == nil {
-		return
-	}
 	if withHelper, ok := l.sink.(CallStackHelperLogSink); ok {
 		withHelper.GetCallStackHelper()()
 	}
@@ -304,9 +284,6 @@ func (l Logger) Error(err error, msg string, keysAndValues ...interface{}) {
 // level means a log message is less important.  Negative V-levels are treated
 // as 0.
 func (l Logger) V(level int) Logger {
-	if l.sink == nil {
-		return l
-	}
 	if level < 0 {
 		level = 0
 	}
@@ -317,9 +294,6 @@ func (l Logger) V(level int) Logger {
 // WithValues returns a new Logger instance with additional key/value pairs.
 // See Info for documentation on how key/value pairs work.
 func (l Logger) WithValues(keysAndValues ...interface{}) Logger {
-	if l.sink == nil {
-		return l
-	}
 	l.setSink(l.sink.WithValues(keysAndValues...))
 	return l
 }
@@ -330,9 +304,6 @@ func (l Logger) WithValues(keysAndValues ...interface{}) Logger {
 // contain only letters, digits, and hyphens (see the package documentation for
 // more information).
 func (l Logger) WithName(name string) Logger {
-	if l.sink == nil {
-		return l
-	}
 	l.setSink(l.sink.WithName(name))
 	return l
 }
@@ -353,9 +324,6 @@ func (l Logger) WithName(name string) Logger {
 // WithCallDepth(1) because it works with implementions that support the
 // CallDepthLogSink and/or CallStackHelperLogSink interfaces.
 func (l Logger) WithCallDepth(depth int) Logger {
-	if l.sink == nil {
-		return l
-	}
 	if withCallDepth, ok := l.sink.(CallDepthLogSink); ok {
 		l.setSink(withCallDepth.WithCallDepth(depth))
 	}
@@ -377,9 +345,6 @@ func (l Logger) WithCallDepth(depth int) Logger {
 // implementation does not support either of these, the original Logger will be
 // returned.
 func (l Logger) WithCallStackHelper() (func(), Logger) {
-	if l.sink == nil {
-		return func() {}, l
-	}
 	var helper func()
 	if withCallDepth, ok := l.sink.(CallDepthLogSink); ok {
 		l.setSink(withCallDepth.WithCallDepth(1))
@@ -392,11 +357,6 @@ func (l Logger) WithCallStackHelper() (func(), Logger) {
 	return helper, l
 }
 
-// IsZero returns true if this logger is an uninitialized zero value
-func (l Logger) IsZero() bool {
-	return l.sink == nil
-}
-
 // contextKey is how we find Loggers in a context.Context.
 type contextKey struct{}
 
@@ -482,7 +442,7 @@ type LogSink interface {
 	WithName(name string) LogSink
 }
 
-// CallDepthLogSink represents a LogSink that knows how to climb the call stack
+// CallDepthLogSink represents a Logger that knows how to climb the call stack
 // to identify the original call site and can offset the depth by a specified
 // number of frames.  This is useful for users who have helper functions
 // between the "real" call site and the actual calls to Logger methods.
@@ -507,7 +467,7 @@ type CallDepthLogSink interface {
 	WithCallDepth(depth int) LogSink
 }
 
-// CallStackHelperLogSink represents a LogSink that knows how to climb
+// CallStackHelperLogSink represents a Logger that knows how to climb
 // the call stack to identify the original call site and can skip
 // intermediate helper functions if they mark themselves as
 // helper. Go's testing package uses that approach.
diff --git a/vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md b/vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md
index 5e779fe6..ccd4f170 100644
--- a/vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md
+++ b/vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md
@@ -1,9 +1,3 @@
-## 2.9.2
-
-### Maintenance
-- Bump github.com/go-task/slim-sprig (#1167) [3fcc5bf]
-- Bump github.com/onsi/gomega from 1.27.3 to 1.27.4 (#1163) [6143ffe]
-
 ## 2.9.1
 
 ### Fixes
diff --git a/vendor/github.com/onsi/ginkgo/v2/types/version.go b/vendor/github.com/onsi/ginkgo/v2/types/version.go
index 8e7f7404..0fb1054f 100644
--- a/vendor/github.com/onsi/ginkgo/v2/types/version.go
+++ b/vendor/github.com/onsi/ginkgo/v2/types/version.go
@@ -1,3 +1,3 @@
 package types
 
-const VERSION = "2.9.2"
+const VERSION = "2.9.1"
diff --git a/vendor/github.com/onsi/gomega/CHANGELOG.md b/vendor/github.com/onsi/gomega/CHANGELOG.md
index ef428f6f..e702e3c9 100644
--- a/vendor/github.com/onsi/gomega/CHANGELOG.md
+++ b/vendor/github.com/onsi/gomega/CHANGELOG.md
@@ -1,17 +1,3 @@
-## 1.27.6
-
-### Fixes
-- Allow collections matchers to work correctly when expected has nil elements [60e7cf3]
-
-### Maintenance
-- updates MatchError godoc comment to also accept a Gomega matcher (#654) [67b869d]
-
-## 1.27.5
-
-### Maintenance
-- Bump github.com/onsi/ginkgo/v2 from 2.9.1 to 2.9.2 (#653) [a215021]
-- Bump github.com/go-task/slim-sprig (#652) [a26fed8]
-
 ## 1.27.4
 
 ### Fixes
diff --git a/vendor/github.com/onsi/gomega/gomega_dsl.go b/vendor/github.com/onsi/gomega/gomega_dsl.go
index 872592bf..e37251d8 100644
--- a/vendor/github.com/onsi/gomega/gomega_dsl.go
+++ b/vendor/github.com/onsi/gomega/gomega_dsl.go
@@ -22,7 +22,7 @@ import (
 	"github.com/onsi/gomega/types"
 )
 
-const GOMEGA_VERSION = "1.27.6"
+const GOMEGA_VERSION = "1.27.4"
 
 const nilGomegaPanic = `You are trying to make an assertion, but haven't registered Gomega's fail handler.
 If you're using Ginkgo then you probably forgot to put your assertion in an It().
diff --git a/vendor/github.com/onsi/gomega/matchers.go b/vendor/github.com/onsi/gomega/matchers.go
index b832f3db..44056ad6 100644
--- a/vendor/github.com/onsi/gomega/matchers.go
+++ b/vendor/github.com/onsi/gomega/matchers.go
@@ -87,17 +87,14 @@ func Succeed() types.GomegaMatcher {
 	return &matchers.SucceedMatcher{}
 }
 
-// MatchError succeeds if actual is a non-nil error that matches the passed in
-// string, error, or matcher.
+// MatchError succeeds if actual is a non-nil error that matches the passed in string/error.
 //
 // These are valid use-cases:
 //
-//  Expect(err).Should(MatchError("an error")) //asserts that err.Error() == "an error"
-//  Expect(err).Should(MatchError(SomeError)) //asserts that err == SomeError (via reflect.DeepEqual)
-//  Expect(err).Should(MatchError(ContainsSubstring("sprocket not found"))) // asserts that edrr.Error() contains substring "sprocket not found"
+//	Expect(err).Should(MatchError("an error")) //asserts that err.Error() == "an error"
+//	Expect(err).Should(MatchError(SomeError)) //asserts that err == SomeError (via reflect.DeepEqual)
 //
-// It is an error for err to be nil or an object that does not implement the
-// Error interface
+// It is an error for err to be nil or an object that does not implement the Error interface
 func MatchError(expected interface{}) types.GomegaMatcher {
 	return &matchers.MatchErrorMatcher{
 		Expected: expected,
diff --git a/vendor/github.com/onsi/gomega/matchers/consist_of.go b/vendor/github.com/onsi/gomega/matchers/consist_of.go
index f69037a4..e8ef0dee 100644
--- a/vendor/github.com/onsi/gomega/matchers/consist_of.go
+++ b/vendor/github.com/onsi/gomega/matchers/consist_of.go
@@ -48,13 +48,11 @@ func neighbours(value, matcher interface{}) (bool, error) {
 
 func equalMatchersToElements(matchers []interface{}) (elements []interface{}) {
 	for _, matcher := range matchers {
-		if equalMatcher, ok := matcher.(*EqualMatcher); ok {
-			elements = append(elements, equalMatcher.Expected)
-		} else if _, ok := matcher.(*BeNilMatcher); ok {
-			elements = append(elements, nil)
-		} else {
-			elements = append(elements, matcher)
+		equalMatcher, ok := matcher.(*EqualMatcher)
+		if ok {
+			matcher = equalMatcher.Expected
 		}
+		elements = append(elements, matcher)
 	}
 	return
 }
@@ -74,13 +72,11 @@ func flatten(elems []interface{}) []interface{} {
 
 func matchers(expectedElems []interface{}) (matchers []interface{}) {
 	for _, e := range flatten(expectedElems) {
-		if e == nil {
-			matchers = append(matchers, &BeNilMatcher{})
-		} else if matcher, isMatcher := e.(omegaMatcher); isMatcher {
-			matchers = append(matchers, matcher)
-		} else {
-			matchers = append(matchers, &EqualMatcher{Expected: e})
+		matcher, isMatcher := e.(omegaMatcher)
+		if !isMatcher {
+			matcher = &EqualMatcher{Expected: e}
 		}
+		matchers = append(matchers, matcher)
 	}
 	return
 }
@@ -93,14 +89,9 @@ func presentable(elems []interface{}) interface{} {
 	}
 
 	sv := reflect.ValueOf(elems)
-	firstEl := sv.Index(0)
-	if firstEl.IsNil() {
-		return elems
-	}
-	tt := firstEl.Elem().Type()
+	tt := sv.Index(0).Elem().Type()
 	for i := 1; i < sv.Len(); i++ {
-		el := sv.Index(i)
-		if el.IsNil() || (sv.Index(i).Elem().Type() != tt) {
+		if sv.Index(i).Elem().Type() != tt {
 			return elems
 		}
 	}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 9c75d3af..ad999013 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -122,7 +122,7 @@ github.com/evanphx/json-patch/v5
 # github.com/fsnotify/fsnotify v1.6.0
 ## explicit; go 1.16
 github.com/fsnotify/fsnotify
-# github.com/go-logr/logr v1.2.4
+# github.com/go-logr/logr v1.2.3
 ## explicit; go 1.16
 github.com/go-logr/logr
 github.com/go-logr/logr/funcr
@@ -139,7 +139,7 @@ github.com/go-openapi/jsonreference/internal
 # github.com/go-openapi/swag v0.22.3
 ## explicit; go 1.18
 github.com/go-openapi/swag
-# github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572
+# github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0
 ## explicit; go 1.13
 github.com/go-task/slim-sprig
 # github.com/gobuffalo/flect v0.3.0
@@ -280,7 +280,7 @@ github.com/modern-go/reflect2
 # github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822
 ## explicit
 github.com/munnerz/goautoneg
-# github.com/onsi/ginkgo/v2 v2.9.2
+# github.com/onsi/ginkgo/v2 v2.9.1
 ## explicit; go 1.18
 github.com/onsi/ginkgo/v2
 github.com/onsi/ginkgo/v2/config
@@ -302,7 +302,7 @@ github.com/onsi/ginkgo/v2/internal/parallel_support
 github.com/onsi/ginkgo/v2/internal/testingtproxy
 github.com/onsi/ginkgo/v2/reporters
 github.com/onsi/ginkgo/v2/types
-# github.com/onsi/gomega v1.27.6
+# github.com/onsi/gomega v1.27.4
 ## explicit; go 1.18
 github.com/onsi/gomega
 github.com/onsi/gomega/format


Test patch:
diff --git a/pkg/services/baremetal/baremetal/baremetal_test.go b/pkg/services/baremetal/baremetal/baremetal_test.go
index 997a5466..53377e0c 100644
--- a/pkg/services/baremetal/baremetal/baremetal_test.go
+++ b/pkg/services/baremetal/baremetal/baremetal_test.go
@@ -794,7 +794,7 @@ var _ = Describe("Test splitHostKey", func() {
 var _ = Describe("Test checkForRequeueError", func() {
 	type testCaseCheckForRequeueError struct {
 		err            error
-		expectedResult reconcile.Result
+		expectedResult *reconcile.Result
 		expectedErrMsg string
 	}
 
@@ -814,17 +814,17 @@ var _ = Describe("Test checkForRequeueError", func() {
 		},
 		Entry("Nil error", testCaseCheckForRequeueError{
 			err:            nil,
-			expectedResult: reconcile.Result{},
+			expectedResult: nil,
 			expectedErrMsg: "",
 		}),
 		Entry("Requeue error", testCaseCheckForRequeueError{
 			err:            &scope.RequeueAfterError{RequeueAfter: 30 * time.Second},
-			expectedResult: reconcile.Result{Requeue: true, RequeueAfter: 30 * time.Second},
+			expectedResult: &reconcile.Result{Requeue: true, RequeueAfter: 30 * time.Second},
 			expectedErrMsg: "",
 		}),
 		Entry("Other error", testCaseCheckForRequeueError{
 			err:            fmt.Errorf("other error"),
-			expectedResult: reconcile.Result{},
+			expectedResult: nil,
 			expectedErrMsg: "test message: other error",
 		}),
 	)
diff --git a/pkg/services/hcloud/client/fake/hcloud_client_test.go b/pkg/services/hcloud/client/fake/hcloud_client_test.go
index 405bddc2..54314f9b 100644
--- a/pkg/services/hcloud/client/fake/hcloud_client_test.go
+++ b/pkg/services/hcloud/client/fake/hcloud_client_test.go
@@ -28,13 +28,11 @@ import (
 
 const labelSelector = "key1==val1"
 
-var (
-	factory = fake.NewHCloudClientFactory()
-	ctx     = context.Background()
-)
+var factory = fake.NewHCloudClientFactory()
+var ctx = context.Background()
 
 var _ = Describe("Load balancer", func() {
-	opts := hcloud.LoadBalancerCreateOpts{
+	var opts = hcloud.LoadBalancerCreateOpts{
 		Name: "lb-name",
 		Labels: map[string]string{
 			"key1": "val1",
@@ -58,7 +56,7 @@ var _ = Describe("Load balancer", func() {
 	var listOpts hcloud.LoadBalancerListOpts
 	listOpts.LabelSelector = labelSelector
 
-	networkOpts := hcloud.NetworkCreateOpts{
+	var networkOpts = hcloud.NetworkCreateOpts{
 		Name: "network-name",
 		Labels: map[string]string{
 			"key1": "val1",
@@ -68,7 +66,7 @@ var _ = Describe("Load balancer", func() {
 		Subnets: []hcloud.NetworkSubnet{{IPRange: &net.IPNet{IP: net.IP("1.2.3.6")}}},
 	}
 
-	client := factory.NewClient("")
+	var client = factory.NewClient("")
 
 	var lb *hcloud.LoadBalancer
 	var network *hcloud.Network
@@ -409,9 +407,9 @@ var _ = Describe("Load balancer", func() {
 		Expect(err).ToNot(Succeed())
 	})
 
-	_ = Describe("Images", func() {
+	var _ = Describe("Images", func() {
 		var listOpts hcloud.ImageListOpts
-		client := factory.NewClient("")
+		var client = factory.NewClient("")
 		BeforeEach(func() {
 			listOpts.LabelSelector = labelSelector
 		})
@@ -427,9 +425,9 @@ var _ = Describe("Server", func() {
 	var listOpts hcloud.ServerListOpts
 	listOpts.LabelSelector = labelSelector
 
-	client := factory.NewClient("")
+	var client = factory.NewClient("")
 
-	opts := hcloud.ServerCreateOpts{
+	var opts = hcloud.ServerCreateOpts{
 		Name: "test-server",
 		Labels: map[string]string{
 			"key1": "val1",
@@ -506,13 +504,6 @@ var _ = Describe("Server", func() {
 		Expect(resp[0].ID).To(Equal(server.ID))
 	})
 
-	It("gets a server", func() {
-		resp, err := client.GetServer(ctx, 1)
-		Expect(err).To(Succeed())
-		Expect(resp).ToNot(BeNil())
-		Expect(resp.ID).To(Equal(server.ID))
-	})
-
 	It("shuts a server down", func() {
 		Expect(server.Status).To(Equal(hcloud.ServerStatusRunning))
 		_, err := client.ShutdownServer(ctx, server)
@@ -593,9 +584,9 @@ var _ = Describe("Network", func() {
 	var listOpts hcloud.NetworkListOpts
 	listOpts.LabelSelector = labelSelector
 
-	client := factory.NewClient("")
+	var client = factory.NewClient("")
 
-	opts := hcloud.NetworkCreateOpts{
+	var opts = hcloud.NetworkCreateOpts{
 		Name: "test-network",
 		Labels: map[string]string{
 			"key1": "val1",
@@ -650,7 +641,7 @@ var _ = Describe("Placement groups", func() {
 	var listOpts hcloud.PlacementGroupListOpts
 	listOpts.LabelSelector = labelSelector
 
-	opts := hcloud.PlacementGroupCreateOpts{
+	var opts = hcloud.PlacementGroupCreateOpts{
 		Name: "placement-group-name",
 		Labels: map[string]string{
 			"key1": "val1",
@@ -659,7 +650,7 @@ var _ = Describe("Placement groups", func() {
 		Type: "stream",
 	}
 
-	client := factory.NewClient("")
+	var client = factory.NewClient("")
 
 	var server *hcloud.Server
 	var placementGroup *hcloud.PlacementGroup
diff --git a/pkg/services/hcloud/server/server_test.go b/pkg/services/hcloud/server/server_test.go
index c1b2053a..192a88d5 100644
--- a/pkg/services/hcloud/server/server_test.go
+++ b/pkg/services/hcloud/server/server_test.go
@@ -199,7 +199,7 @@ var _ = Describe("handleServerStatusOff", func() {
 		service := newTestService(hcloudMachine, client)
 		res, err := service.handleServerStatusOff(context.Background(), server)
 		Expect(err).To(Succeed())
-		Expect(res).Should(Equal(reconcile.Result{RequeueAfter: 30 * time.Second}))
+		Expect(res).Should(Equal(&reconcile.Result{RequeueAfter: 30 * time.Second}))
 		Expect(conditions.GetReason(hcloudMachine, infrav1.InstanceReadyCondition)).To(Equal(infrav1.ServerOffReason))
 		Expect(server.Status).To(Equal(hcloud.ServerStatusRunning))
 	})
@@ -209,7 +209,7 @@ var _ = Describe("handleServerStatusOff", func() {
 		service := newTestService(hcloudMachine, client)
 		res, err := service.handleServerStatusOff(context.Background(), server)
 		Expect(err).To(Succeed())
-		Expect(res).Should(Equal(reconcile.Result{RequeueAfter: 30 * time.Second}))
+		Expect(res).Should(Equal(&reconcile.Result{RequeueAfter: 30 * time.Second}))
 		Expect(server.Status).To(Equal(hcloud.ServerStatusRunning))
 		Expect(conditions.GetReason(hcloudMachine, infrav1.InstanceReadyCondition)).To(Equal(infrav1.ServerOffReason))
 	})
@@ -226,8 +226,8 @@ var _ = Describe("handleServerStatusOff", func() {
 		service := newTestService(hcloudMachine, client)
 		res, err := service.handleServerStatusOff(context.Background(), server)
 		Expect(err).To(Succeed())
-		var emptyResult reconcile.Result
-		Expect(res).Should(Equal(emptyResult))
+		var nilResult *reconcile.Result
+		Expect(res).Should(Equal(nilResult))
 		Expect(server.Status).To(Equal(hcloud.ServerStatusOff))
 		Expect(hcloudMachine.Status.FailureMessage).Should(Equal(pointer.String("reached timeout of waiting for machines that are switched off")))
 	})
@@ -237,7 +237,7 @@ var _ = Describe("handleServerStatusOff", func() {
 		service := newTestService(hcloudMachine, client)
 		res, err := service.handleServerStatusOff(context.Background(), server)
 		Expect(err).To(Succeed())
-		Expect(res).Should(Equal(reconcile.Result{RequeueAfter: 30 * time.Second}))
+		Expect(res).Should(Equal(&reconcile.Result{RequeueAfter: 30 * time.Second}))
 		Expect(conditions.GetReason(hcloudMachine, infrav1.InstanceReadyCondition)).To(Equal(infrav1.ServerOffReason))
 		Expect(server.Status).To(Equal(hcloud.ServerStatusRunning))
 	})
diff --git a/pkg/services/hcloud/util/utils_test.go b/pkg/services/hcloud/util/utils_test.go
deleted file mode 100644
index e839a368..00000000
--- a/pkg/services/hcloud/util/utils_test.go
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package hcloudutil
-
-import (
-	"testing"
-
-	. "github.com/onsi/ginkgo/v2"
-	. "github.com/onsi/gomega"
-)
-
-func TestHCloudUtils(t *testing.T) {
-	RegisterFailHandler(Fail)
-	RunSpecs(t, "HCloud utils tests")
-}
-
-var _ = Describe("Test ProviderIDFromServerID", func() {
-	It("generates a correct providerID from a serverID", func() {
-		Expect(ProviderIDFromServerID(42)).To(Equal("hcloud://42"))
-	})
-})
-
-var _ = Describe("Test ServerIDFromProviderID", func() {
-	It("gives the correct error when providerID is nil", func() {
-		_, err := ServerIDFromProviderID(nil)
-		Expect(err).ToNot(BeNil())
-		Expect(err).To(MatchError(ErrNilProviderID))
-	})
-	type testCaseServerIDFromProviderID struct {
-		providerID     string
-		expectServerID int
-		expectError    error
-	}
-
-	DescribeTable("Test ServerIDFromProviderID",
-		func(tc testCaseServerIDFromProviderID) {
-			serverID, err := ServerIDFromProviderID(&tc.providerID)
-			Expect(serverID).Should(Equal(tc.expectServerID))
-			if tc.expectError != nil {
-				Expect(err).ToNot(BeNil())
-				Expect(err).Should(MatchError(tc.expectError))
-			} else {
-				Expect(err).To(BeNil())
-			}
-		},
-		Entry("valid providerID", testCaseServerIDFromProviderID{
-			providerID:     "hcloud://42",
-			expectServerID: 42,
-			expectError:    nil,
-		}),
-		Entry("invalid serverID", testCaseServerIDFromProviderID{
-			providerID:     "hcloud://serverID",
-			expectServerID: 0,
-			expectError:    ErrInvalidProviderID,
-		}),
-		Entry("invalid providerID 1", testCaseServerIDFromProviderID{
-			providerID:     "hcloud::serverID",
-			expectServerID: 0,
-			expectError:    ErrInvalidProviderID,
-		}),
-		Entry("invalid providerID 2", testCaseServerIDFromProviderID{
-			providerID:     "hcloud://serverID://s",
-			expectServerID: 0,
-			expectError:    ErrInvalidProviderID,
-		}),
-	)
-})
diff --git a/test/e2e/config/hetzner-ci.yaml b/test/e2e/config/hetzner-ci.yaml
index 2364dff6..e4822a85 100644
--- a/test/e2e/config/hetzner-ci.yaml
+++ b/test/e2e/config/hetzner-ci.yaml
@@ -157,18 +157,7 @@ variables:
   REDACT_LOG_SCRIPT: "../../hack/log/redact.sh"
 
 intervals:
-  default/wait-cluster: ["20m", "10s"]
-  default/wait-control-plane: ["30m", "10s"]
-  default/wait-worker-nodes: ["15m", "10s"]
-  default/wait-controllers: ["5m", "10s"]
-  default/wait-delete-cluster: ["20m", "10s"]
-  default/wait-machine-upgrade: ["20m", "10s"]
-  default/wait-machine-status: ["20m", "10s"]
-  default/wait-failed-machine-status: ["2m", "10s"]
-  default/wait-machine-remediation: ["15m", "10s"]
-  default/wait-deployment: ["5m", "10s"]
-  default/wait-job: ["5m", "10s"]
-  default/wait-nodes-ready: ["15m", "10s"]
-  default/wait-service: ["3m", "10s"]
-  node-drain/wait-deployment-available: ["3m", "10s"]
-  node-drain/wait-machine-deleted: ["15m", "10s"]
+  default/wait-cluster: ["5m", "10s"] ## wait until Infrastructure == ready and ControlPlaneEndpoint is valid
+  default/wait-control-plane: ["15m", "10s"] ## wait until first control plane is ready
+  default/wait-worker-nodes: ["20m", "10s"] ## wait until all workers are ready from the moment when the control plane is ready
+  default/wait-delete-cluster: ["20m", "10s"] ## wait until cluster is deleted
\ No newline at end of file
diff --git a/test/e2e/config/hetzner.yaml b/test/e2e/config/hetzner.yaml
index 97712f91..b2baac0d 100644
--- a/test/e2e/config/hetzner.yaml
+++ b/test/e2e/config/hetzner.yaml
@@ -163,18 +163,7 @@ variables:
   REDACT_LOG_SCRIPT: "../../hack/log/redact.sh"
 
 intervals:
-  default/wait-cluster: ["20m", "10s"]
-  default/wait-control-plane: ["30m", "10s"]
-  default/wait-worker-nodes: ["15m", "10s"]
-  default/wait-controllers: ["5m", "10s"]
-  default/wait-delete-cluster: ["20m", "10s"]
-  default/wait-machine-upgrade: ["20m", "10s"]
-  default/wait-machine-status: ["20m", "10s"]
-  default/wait-failed-machine-status: ["2m", "10s"]
-  default/wait-machine-remediation: ["15m", "10s"]
-  default/wait-deployment: ["5m", "10s"]
-  default/wait-job: ["5m", "10s"]
-  default/wait-nodes-ready: ["15m", "10s"]
-  default/wait-service: ["3m", "10s"]
-  node-drain/wait-deployment-available: ["3m", "10s"]
-  node-drain/wait-machine-deleted: ["15m", "10s"]
+  default/wait-cluster: ["5m", "10s"] ## wait until Infrastructure == ready and ControlPlaneEndpoint is valid
+  default/wait-control-plane: ["15m", "10s"] ## wait until first control plane is ready
+  default/wait-worker-nodes: ["20m", "10s"] ## wait until all workers are ready from the moment when the control plane is ready
+  default/wait-delete-cluster: ["20m", "10s"] ## wait until cluster is deleted
\ No newline at end of file
diff --git a/test/helpers/envtest.go b/test/helpers/envtest.go
index 8ca7a782..f34b7f99 100644
--- a/test/helpers/envtest.go
+++ b/test/helpers/envtest.go
@@ -168,12 +168,6 @@ func NewTestEnvironment() *TestEnvironment {
 	if err := (&infrav1.HetznerBareMetalRemediationTemplate{}).SetupWebhookWithManager(mgr); err != nil {
 		klog.Fatalf("failed to set up webhook with manager for HetznerBareMetalRemediationTemplate: %s", err)
 	}
-	if err := (&infrav1.HCloudRemediation{}).SetupWebhookWithManager(mgr); err != nil {
-		klog.Fatalf("failed to set up webhook with manager for HCloudRemediation: %s", err)
-	}
-	if err := (&infrav1.HCloudRemediationTemplate{}).SetupWebhookWithManager(mgr); err != nil {
-		klog.Fatalf("failed to set up webhook with manager for HCloudRemediationTemplate: %s", err)
-	}
 	// Create a fake HCloudClientFactory
 	hcloudClientFactory := fakeclient.NewHCloudClientFactory()