Repository: syself/cluster-api-provider-hetzner
Pull request #900 (2023-09-11 11:49:04)

:seedling: Refactor conditions of HetznerCluster
**What this PR does / why we need it**:
Refactoring conditions to improve naming and set more precise conditions.

Actively remove deprecated conditions from objects so that they are not stuck on existing objects from older versions of the operator.

**TODOs**:
- [x] squash commits
- [ ] include documentation
- [ ] add unit tests




Patch:
diff --git a/api/v1beta1/conditions_const.go b/api/v1beta1/conditions_const.go
index edc7ac3c..53760601 100644
--- a/api/v1beta1/conditions_const.go
+++ b/api/v1beta1/conditions_const.go
@@ -21,21 +21,16 @@ import clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 const (
 	// LoadBalancerReadyCondition reports on whether a control plane load balancer was successfully reconciled.
 	LoadBalancerReadyCondition clusterv1.ConditionType = "LoadBalancerReady"
-	// LoadBalancerFailedReason used when an error occurs during load balancer reconciliation.
-	LoadBalancerFailedReason = "LoadBalancerFailed"
-	// LoadBalancerNotFoundReason used when a load balancer could not be found.
-	LoadBalancerNotFoundReason = "LoadBalancerNotFound"
+	// LoadBalancerCreateFailedReason used when an error occurs during load balancer create.
+	LoadBalancerCreateFailedReason = "LoadBalancerCreateFailed"
+	// LoadBalancerUpdateFailedReason used when an error occurs during load balancer update.
+	LoadBalancerUpdateFailedReason = "LoadBalancerUpdateFailed"
+	// LoadBalancerServiceSyncFailedReason used when an error occurs while syncing services of load balancer.
+	LoadBalancerServiceSyncFailedReason = "LoadBalancerServiceSyncFailed"
 	// LoadBalancerFailedToOwnReason used when no owned label could be set on a load balancer.
 	LoadBalancerFailedToOwnReason = "LoadBalancerFailedToOwn"
 )
 
-const (
-	// LoadBalancerAttachedToNetworkCondition reports on whether the load balancer is attached to a network.
-	LoadBalancerAttachedToNetworkCondition clusterv1.ConditionType = "LoadBalancerAttachedToNetwork"
-	// LoadBalancerNoNetworkFoundReason is used when no network could be found.
-	LoadBalancerNoNetworkFoundReason = "LoadBalancerNoNetworkFound"
-)
-
 const (
 	// ServerCreateSucceededCondition reports on current status of the instance. Ready indicates the instance is in a Running state.
 	ServerCreateSucceededCondition clusterv1.ConditionType = "ServerCreateSucceeded"
@@ -54,6 +49,9 @@ const (
 	ServerStartingReason = "ServerStarting"
 	// ServerOffReason instance is off.
 	ServerOffReason = "ServerOff"
+)
+
+const (
 	// NetworkAttachFailedReason is used when server could not be attached to network.
 	NetworkAttachFailedReason = "NetworkAttachFailed"
 	// LoadBalancerAttachFailedReason is used when server could not be attached to network.
@@ -68,17 +66,17 @@ const (
 )
 
 const (
-	// NetworkAttachedCondition reports on whether there is a network attached to the cluster.
-	NetworkAttachedCondition clusterv1.ConditionType = "NetworkAttached"
-	// NetworkUnreachableReason indicates that network is unreachable.
-	NetworkUnreachableReason = "NetworkUnreachable"
+	// NetworkReadyCondition reports on whether the network is ready.
+	NetworkReadyCondition clusterv1.ConditionType = "NetworkReady"
+	// NetworkReconcileFailedReason indicates that reconciling the network failed.
+	NetworkReconcileFailedReason = "NetworkReconcileFailed"
 )
 
 const (
 	// PlacementGroupsSyncedCondition reports on whether the placement groups are successfully synced.
 	PlacementGroupsSyncedCondition clusterv1.ConditionType = "PlacementGroupsSynced"
-	// PlacementGroupsUnreachableReason indicates that network is disabled.
-	PlacementGroupsUnreachableReason = "PlacementGroupsUnreachable"
+	// PlacementGroupsSyncFailedReason indicates that syncing the placement groups failed.
+	PlacementGroupsSyncFailedReason = "PlacementGroupsSyncFailed"
 )
 
 const (
@@ -91,12 +89,16 @@ const (
 )
 
 const (
-	// HetznerClusterTargetClusterReadyCondition reports on whether the kubeconfig in the target cluster is ready.
-	HetznerClusterTargetClusterReadyCondition clusterv1.ConditionType = "HetznerClusterTargetClusterReady"
+	// TargetClusterReadyCondition reports on whether the kubeconfig in the target cluster is ready.
+	TargetClusterReadyCondition clusterv1.ConditionType = "TargetClusterReady"
 	// KubeConfigNotFoundReason indicates that the Kubeconfig could not be found.
 	KubeConfigNotFoundReason = "KubeConfigNotFound"
 	// KubeAPIServerNotRespondingReason indicates that the api server cannot be reached.
 	KubeAPIServerNotRespondingReason = "KubeAPIServerNotResponding"
+	// TargetClusterCreateFailedReason indicates that the target cluster could not be created.
+	TargetClusterCreateFailedReason = "TargetClusterCreateFailed"
+	// TargetSecretSyncFailedReason indicates that the target secret could not be synced.
+	TargetSecretSyncFailedReason = "TargetSecretSyncFailed"
 )
 
 const (
@@ -150,3 +152,16 @@ const (
 	// AssociateBMHCondition reports on whether the Hetzner cluster is in ready state.
 	AssociateBMHCondition clusterv1.ConditionType = "AssociateBMHCondition"
 )
+
+// deprecated conditions.
+
+const (
+	// HetznerClusterTargetClusterReadyCondition reports on whether the kubeconfig in the target cluster is ready.
+	HetznerClusterTargetClusterReadyCondition clusterv1.ConditionType = "HetznerClusterTargetClusterReady"
+
+	// NetworkAttachedCondition reports on whether there is a network attached to the cluster.
+	NetworkAttachedCondition clusterv1.ConditionType = "NetworkAttached"
+
+	// LoadBalancerAttachedToNetworkCondition reports on whether the load balancer is attached to a network.
+	LoadBalancerAttachedToNetworkCondition clusterv1.ConditionType = "LoadBalancerAttachedToNetwork"
+)
diff --git a/controllers/hetznercluster_controller.go b/controllers/hetznercluster_controller.go
index 3a31c3cf..4f3fd8c1 100644
--- a/controllers/hetznercluster_controller.go
+++ b/controllers/hetznercluster_controller.go
@@ -182,7 +182,6 @@ func (r *HetznerClusterReconciler) reconcileNormal(ctx context.Context, clusterS
 
 	// reconcile the network
 	if err := network.NewService(clusterScope).Reconcile(ctx); err != nil {
-		conditions.MarkFalse(hetznerCluster, infrav1.NetworkAttachedCondition, infrav1.NetworkUnreachableReason, clusterv1.ConditionSeverityError, err.Error())
 		return reconcile.Result{}, fmt.Errorf("failed to reconcile network for HetznerCluster %s/%s: %w", hetznerCluster.Namespace, hetznerCluster.Name, err)
 	}
 
@@ -197,14 +196,10 @@ func (r *HetznerClusterReconciler) reconcileNormal(ctx context.Context, clusterS
 		return reconcile.Result{}, fmt.Errorf("failed to reconcile load balancers for HetznerCluster %s/%s: %w", hetznerCluster.Namespace, hetznerCluster.Name, err)
 	}
 
-	conditions.MarkTrue(hetznerCluster, infrav1.LoadBalancerReadyCondition)
-
 	// reconcile the placement groups
 	if err := placementgroup.NewService(clusterScope).Reconcile(ctx); err != nil {
-		conditions.MarkFalse(hetznerCluster, infrav1.PlacementGroupsSyncedCondition, infrav1.PlacementGroupsUnreachableReason, clusterv1.ConditionSeverityError, err.Error())
 		return reconcile.Result{}, fmt.Errorf("failed to reconcile placement groups for HetznerCluster %s/%s: %w", hetznerCluster.Namespace, hetznerCluster.Name, err)
 	}
-	conditions.MarkTrue(hetznerCluster, infrav1.PlacementGroupsSyncedCondition)
 
 	if hetznerCluster.Spec.ControlPlaneLoadBalancer.Enabled {
 		if hetznerCluster.Status.ControlPlaneLoadBalancer.IPv4 != "<nil>" {
@@ -231,6 +226,9 @@ func (r *HetznerClusterReconciler) reconcileNormal(ctx context.Context, clusterS
 		hetznerCluster.Status.Ready = true
 	}
 
+	// delete deprecated conditions of old clusters
+	conditions.Delete(clusterScope.HetznerCluster, infrav1.HetznerClusterTargetClusterReadyCondition)
+
 	result, err := r.reconcileTargetClusterManager(ctx, clusterScope)
 	if err != nil {
 		return reconcile.Result{}, fmt.Errorf("failed to reconcile target cluster manager: %w", err)
@@ -240,9 +238,20 @@ func (r *HetznerClusterReconciler) reconcileNormal(ctx context.Context, clusterS
 	}
 
 	if err := reconcileTargetSecret(ctx, clusterScope); err != nil {
-		return reconcile.Result{}, fmt.Errorf("failed to reconcile target secret: %w", err)
+		reterr := fmt.Errorf("failed to reconcile target secret: %w", err)
+		conditions.MarkFalse(
+			clusterScope.HetznerCluster,
+			infrav1.TargetClusterReadyCondition,
+			infrav1.TargetSecretSyncFailedReason,
+			clusterv1.ConditionSeverityError,
+			reterr.Error(),
+		)
+		return reconcile.Result{}, reterr
 	}
 
+	// target cluster is ready
+	conditions.MarkTrue(hetznerCluster, infrav1.TargetClusterReadyCondition)
+
 	return reconcile.Result{}, nil
 }
 
@@ -522,6 +531,14 @@ func (r *HetznerClusterReconciler) reconcileTargetClusterManager(ctx context.Con
 		// create a new cluster manager
 		m, err := r.newTargetClusterManager(ctx, clusterScope)
 		if err != nil {
+			conditions.MarkFalse(
+				clusterScope.HetznerCluster,
+				infrav1.TargetClusterReadyCondition,
+				infrav1.TargetClusterCreateFailedReason,
+				clusterv1.ConditionSeverityError,
+				err.Error(),
+			)
+
 			return res, fmt.Errorf("failed to create a clusterManager for HetznerCluster %s/%s: %w",
 				clusterScope.HetznerCluster.Namespace,
 				clusterScope.HetznerCluster.Name,
@@ -546,6 +563,13 @@ func (r *HetznerClusterReconciler) reconcileTargetClusterManager(ctx context.Con
 
 			if err := m.Start(ctx); err != nil {
 				clusterScope.Error(err, "failed to start a targetClusterManager")
+				conditions.MarkFalse(
+					clusterScope.HetznerCluster,
+					infrav1.TargetClusterReadyCondition,
+					infrav1.TargetClusterCreateFailedReason,
+					clusterv1.ConditionSeverityError,
+					"failed to start a targetClusterManager: %s", err.Error(),
+				)
 			} else {
 				clusterScope.Info("stop targetClusterManager")
 			}
@@ -580,7 +604,13 @@ func (r *HetznerClusterReconciler) newTargetClusterManager(ctx context.Context,
 	clientConfig, err := clusterScope.ClientConfig(ctx)
 	if err != nil {
 		if apierrors.IsNotFound(err) {
-			conditions.MarkFalse(hetznerCluster, infrav1.HetznerClusterTargetClusterReadyCondition, infrav1.KubeConfigNotFoundReason, clusterv1.ConditionSeverityInfo, "kubeconfig not found (yet)")
+			conditions.MarkFalse(
+				hetznerCluster,
+				infrav1.TargetClusterReadyCondition,
+				infrav1.KubeConfigNotFoundReason,
+				clusterv1.ConditionSeverityInfo,
+				"kubeconfig not found (yet)",
+			)
 			return nil, nil
 		}
 		return nil, fmt.Errorf("failed to get a clientConfig for the API of HetznerCluster %s/%s: %w", hetznerCluster.Namespace, hetznerCluster.Name, err)
@@ -607,13 +637,16 @@ func (r *HetznerClusterReconciler) newTargetClusterManager(ctx context.Context,
 
 	// Check whether kubeapi server responds
 	if _, err := apiutil.NewDynamicRESTMapper(restConfig, httpClient); err != nil {
-		conditions.MarkFalse(hetznerCluster, infrav1.HetznerClusterTargetClusterReadyCondition, infrav1.KubeAPIServerNotRespondingReason, clusterv1.ConditionSeverityInfo, "kubeapi server not responding (yet)")
+		conditions.MarkFalse(
+			hetznerCluster,
+			infrav1.TargetClusterReadyCondition,
+			infrav1.KubeAPIServerNotRespondingReason,
+			clusterv1.ConditionSeverityInfo,
+			"kubeapi server not responding (yet)",
+		)
 		return nil, nil //nolint:nilerr
 	}
 
-	// target cluster is ready
-	conditions.MarkTrue(hetznerCluster, infrav1.HetznerClusterTargetClusterReadyCondition)
-
 	clusterMgr, err := ctrl.NewManager(
 		restConfig,
 		ctrl.Options{
diff --git a/pkg/services/baremetal/host/utils.go b/pkg/services/baremetal/host/utils.go
index 549e9af5..9e0edada 100644
--- a/pkg/services/baremetal/host/utils.go
+++ b/pkg/services/baremetal/host/utils.go
@@ -54,6 +54,9 @@ SWRAIDLEVEL %v`, hostName, installImageSpec.SwraidLevel)
 PART %s %s %s`, partitions, partition.Mount, partition.FileSystem, partition.Size)
 	}
 
+	// e.g. PART / ext4 all
+	// e.g. PART /boot ext4 1024M
+
 	var lvmDefinitions string
 	for _, lvm := range installImageSpec.LVMDefinitions {
 		lvmDefinitions = fmt.Sprintf(`%s
diff --git a/pkg/services/hcloud/loadbalancer/loadbalancer.go b/pkg/services/hcloud/loadbalancer/loadbalancer.go
index c1c7d66c..0cd3fbaf 100644
--- a/pkg/services/hcloud/loadbalancer/loadbalancer.go
+++ b/pkg/services/hcloud/loadbalancer/loadbalancer.go
@@ -52,6 +52,9 @@ var ErrNoLoadBalancerAvailable = fmt.Errorf("no available load balancer")
 
 // Reconcile implements the life cycle of HCloud load balancers.
 func (s *Service) Reconcile(ctx context.Context) (reconcile.Result, error) {
+	// delete the deprecated condition from existing cluster objects
+	conditions.Delete(s.scope.HetznerCluster, infrav1.LoadBalancerAttachedToNetworkCondition)
+
 	if !s.scope.HetznerCluster.Spec.ControlPlaneLoadBalancer.Enabled {
 		return reconcile.Result{}, nil
 	}
@@ -86,6 +89,13 @@ func (s *Service) Reconcile(ctx context.Context) (reconcile.Result, error) {
 
 	// check whether load balancer name, algorithm or type has been changed
 	if err := s.reconcileLBProperties(ctx, lb); err != nil {
+		conditions.MarkFalse(
+			s.scope.HetznerCluster,
+			infrav1.LoadBalancerReadyCondition,
+			infrav1.LoadBalancerUpdateFailedReason,
+			clusterv1.ConditionSeverityWarning,
+			err.Error(),
+		)
 		return reconcile.Result{}, fmt.Errorf("failed to reconcile load balancer properties: %w", err)
 	}
 
@@ -94,9 +104,17 @@ func (s *Service) Reconcile(ctx context.Context) (reconcile.Result, error) {
 	}
 
 	if err := s.reconcileServices(ctx, lb); err != nil {
+		conditions.MarkFalse(
+			s.scope.HetznerCluster,
+			infrav1.LoadBalancerReadyCondition,
+			infrav1.LoadBalancerServiceSyncFailedReason,
+			clusterv1.ConditionSeverityWarning,
+			err.Error(),
+		)
 		return reconcile.Result{}, fmt.Errorf("failed to reconcile services: %w", err)
 	}
 
+	conditions.MarkTrue(s.scope.HetznerCluster, infrav1.LoadBalancerReadyCondition)
 	return reconcile.Result{}, nil
 }
 
@@ -113,14 +131,15 @@ func (s *Service) reconcileNetworkAttachement(ctx context.Context, lb *hcloud.Lo
 
 	// attach load balancer to network
 	if s.scope.HetznerCluster.Status.Network == nil {
+		err := fmt.Errorf("no network found in object status")
 		conditions.MarkFalse(
 			s.scope.HetznerCluster,
-			infrav1.LoadBalancerAttachedToNetworkCondition,
-			infrav1.LoadBalancerNoNetworkFoundReason,
-			clusterv1.ConditionSeverityInfo,
-			"no network found",
+			infrav1.LoadBalancerReadyCondition,
+			infrav1.NetworkAttachFailedReason,
+			clusterv1.ConditionSeverityWarning,
+			err.Error(),
 		)
-		return nil
+		return err
 	}
 
 	opts := hcloud.LoadBalancerAttachToNetworkOpts{
@@ -140,15 +159,14 @@ func (s *Service) reconcileNetworkAttachement(ctx context.Context, lb *hcloud.Lo
 		record.Warnf(s.scope.HetznerCluster, "FailedAttachLoadBalancer", err.Error())
 		conditions.MarkFalse(
 			s.scope.HetznerCluster,
-			infrav1.LoadBalancerAttachedToNetworkCondition,
-			infrav1.LoadBalancerAttachFailedReason,
+			infrav1.LoadBalancerReadyCondition,
+			infrav1.NetworkAttachFailedReason,
 			clusterv1.ConditionSeverityError,
 			err.Error(),
 		)
 		return err
 	}
 
-	conditions.MarkTrue(s.scope.HetznerCluster, infrav1.LoadBalancerAttachedToNetworkCondition)
 	return nil
 }
 
@@ -264,10 +282,16 @@ func (s *Service) createLoadBalancer(ctx context.Context) (*hcloud.LoadBalancer,
 	opts := createOptsFromSpec(s.scope.HetznerCluster)
 	lb, err := s.scope.HCloudClient.CreateLoadBalancer(ctx, opts)
 	if err != nil {
-		hcloudutil.HandleRateLimitExceeded(s.scope.HetznerCluster, err, "CreateLoadBalancer")
 		err = fmt.Errorf("failed to create load balancer: %w", err)
+		hcloudutil.HandleRateLimitExceeded(s.scope.HetznerCluster, err, "CreateLoadBalancer")
+		conditions.MarkFalse(
+			s.scope.HetznerCluster,
+			infrav1.LoadBalancerReadyCondition,
+			infrav1.LoadBalancerCreateFailedReason,
+			clusterv1.ConditionSeverityError,
+			err.Error(),
+		)
 		record.Warnf(s.scope.HetznerCluster, "FailedCreateLoadBalancer", err.Error())
-		conditions.MarkFalse(s.scope.HetznerCluster, infrav1.LoadBalancerReadyCondition, infrav1.LoadBalancerFailedReason, clusterv1.ConditionSeverityError, err.Error())
 
 		return nil, err
 	}
@@ -380,7 +404,7 @@ func (s *Service) ownExistingLoadBalancer(ctx context.Context) (*hcloud.LoadBala
 		conditions.MarkFalse(
 			s.scope.HetznerCluster,
 			infrav1.LoadBalancerReadyCondition,
-			infrav1.LoadBalancerNotFoundReason,
+			infrav1.LoadBalancerFailedToOwnReason,
 			clusterv1.ConditionSeverityError,
 			fmt.Sprintf("load balancer %q not found", name),
 		)
@@ -396,7 +420,7 @@ func (s *Service) ownExistingLoadBalancer(ctx context.Context) (*hcloud.LoadBala
 				infrav1.LoadBalancerReadyCondition,
 				infrav1.LoadBalancerFailedToOwnReason,
 				clusterv1.ConditionSeverityError,
-				fmt.Sprintf("load balancer %q owned with label %q", name, label),
+				fmt.Sprintf("load balancer %q already owned with label %q", name, label),
 			)
 			return nil, ErrNoLoadBalancerAvailable
 		}
@@ -412,6 +436,13 @@ func (s *Service) ownExistingLoadBalancer(ctx context.Context) (*hcloud.LoadBala
 		hcloudutil.HandleRateLimitExceeded(s.scope.HetznerCluster, err, "UpdateLoadBalancer")
 		err = fmt.Errorf("failed to update load balancer: %w", err)
 		record.Warnf(s.scope.HetznerCluster, "FailedUpdateLoadBalancer", err.Error())
+		conditions.MarkFalse(
+			s.scope.HetznerCluster,
+			infrav1.LoadBalancerReadyCondition,
+			infrav1.LoadBalancerFailedToOwnReason,
+			clusterv1.ConditionSeverityError,
+			err.Error(),
+		)
 		return nil, err
 	}
 
diff --git a/pkg/services/hcloud/network/network.go b/pkg/services/hcloud/network/network.go
index 61d0f4ba..3b1777e0 100644
--- a/pkg/services/hcloud/network/network.go
+++ b/pkg/services/hcloud/network/network.go
@@ -23,6 +23,7 @@ import (
 	"net"
 
 	"github.com/hetznercloud/hcloud-go/hcloud"
+	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	"sigs.k8s.io/cluster-api/util/conditions"
 	"sigs.k8s.io/cluster-api/util/record"
 
@@ -46,10 +47,25 @@ func NewService(scope *scope.ClusterScope) *Service {
 
 // Reconcile implements life cycle of networks.
 func (s *Service) Reconcile(ctx context.Context) (err error) {
+	// delete the deprecated condition from existing cluster objects
+	conditions.Delete(s.scope.HetznerCluster, infrav1.NetworkAttachedCondition)
+
 	if !s.scope.HetznerCluster.Spec.HCloudNetwork.Enabled {
 		return nil
 	}
 
+	defer func() {
+		if err != nil {
+			conditions.MarkFalse(
+				s.scope.HetznerCluster,
+				infrav1.NetworkReadyCondition,
+				infrav1.NetworkReconcileFailedReason,
+				clusterv1.ConditionSeverityWarning,
+				err.Error(),
+			)
+		}
+	}()
+
 	network, err := s.findNetwork(ctx)
 	if err != nil {
 		return fmt.Errorf("failed to find network: %w", err)
@@ -62,8 +78,9 @@ func (s *Service) Reconcile(ctx context.Context) (err error) {
 		}
 	}
 
-	conditions.MarkTrue(s.scope.HetznerCluster, infrav1.NetworkAttachedCondition)
+	conditions.MarkTrue(s.scope.HetznerCluster, infrav1.NetworkReadyCondition)
 	s.scope.HetznerCluster.Status.Network = statusFromHCloudNetwork(network)
+
 	return nil
 }
 
diff --git a/pkg/services/hcloud/placementgroup/placementgroup.go b/pkg/services/hcloud/placementgroup/placementgroup.go
index 2156c738..11d685fb 100644
--- a/pkg/services/hcloud/placementgroup/placementgroup.go
+++ b/pkg/services/hcloud/placementgroup/placementgroup.go
@@ -24,6 +24,8 @@ import (
 	"strings"
 
 	"github.com/hetznercloud/hcloud-go/hcloud"
+	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
+	"sigs.k8s.io/cluster-api/util/conditions"
 	"sigs.k8s.io/cluster-api/util/record"
 
 	infrav1 "github.com/syself/cluster-api-provider-hetzner/api/v1beta1"
@@ -46,6 +48,18 @@ func NewService(scope *scope.ClusterScope) *Service {
 
 // Reconcile implements life cycle of placement groups.
 func (s *Service) Reconcile(ctx context.Context) (err error) {
+	defer func() {
+		if err != nil {
+			conditions.MarkFalse(
+				s.scope.HetznerCluster,
+				infrav1.PlacementGroupsSyncedCondition,
+				infrav1.PlacementGroupsSyncFailedReason,
+				clusterv1.ConditionSeverityWarning,
+				err.Error(),
+			)
+		}
+	}()
+
 	// find placement groups
 	placementGroups, err := s.findPlacementGroups(ctx)
 	if err != nil {
@@ -112,6 +126,8 @@ func (s *Service) Reconcile(ctx context.Context) (err error) {
 	}
 
 	s.scope.HetznerCluster.Status.HCloudPlacementGroups = statusFromHCloudPlacementGroups(placementGroups, s.scope.HetznerCluster.Name)
+	conditions.MarkTrue(s.scope.HetznerCluster, infrav1.PlacementGroupsSyncedCondition)
+
 	return nil
 }
 


Test patch:
diff --git a/controllers/controllers_suite_test.go b/controllers/controllers_suite_test.go
index 96e581d5..29b14fd4 100644
--- a/controllers/controllers_suite_test.go
+++ b/controllers/controllers_suite_test.go
@@ -40,7 +40,7 @@ import (
 
 const (
 	defaultPodNamespace = "caph-system"
-	timeout             = time.Second * 3
+	timeout             = time.Second * 5
 )
 
 func TestControllers(t *testing.T) {
diff --git a/controllers/hetznercluster_controller_test.go b/controllers/hetznercluster_controller_test.go
index 742f1038..088d60fe 100644
--- a/controllers/hetznercluster_controller_test.go
+++ b/controllers/hetznercluster_controller_test.go
@@ -463,7 +463,7 @@ var _ = Describe("Hetzner ClusterReconciler", func() {
 					return false
 				}
 
-				return isPresentAndFalseWithReason(key, instance, infrav1.LoadBalancerReadyCondition, infrav1.LoadBalancerNotFoundReason)
+				return isPresentAndFalseWithReason(key, instance, infrav1.LoadBalancerReadyCondition, infrav1.LoadBalancerFailedToOwnReason)
 			}, timeout, time.Second).Should(BeTrue())
 		})
 	})
@@ -803,9 +803,9 @@ var _ = Describe("Hetzner ClusterReconciler", func() {
 						return false
 					}
 					if expectedConditionState {
-						return isPresentAndTrue(key, instance, infrav1.NetworkAttachedCondition)
+						return isPresentAndTrue(key, instance, infrav1.NetworkReadyCondition)
 					}
-					return isPresentAndFalseWithReason(key, instance, infrav1.NetworkAttachedCondition, expectedReason)
+					return isPresentAndFalseWithReason(key, instance, infrav1.NetworkReadyCondition, expectedReason)
 				}, timeout).Should(BeTrue())
 			},
 			Entry("with network", getDefaultHetznerClusterSpec(), true, ""),