Repository: syself/cluster-api-provider-hetzner
Pull request #1430 (2024-08-09 11:02:45)

:seedling: Update Update Golang Dependencies group (minor)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence | Type | Update |
|---|---|---|---|---|---|---|---|
| [github.com/onsi/ginkgo/v2](https://togithub.com/onsi/ginkgo) | `v2.19.0` -> `v2.20.0` | [![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2fonsi%2fginkgo%2fv2/v2.20.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/go/github.com%2fonsi%2fginkgo%2fv2/v2.20.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/go/github.com%2fonsi%2fginkgo%2fv2/v2.19.0/v2.20.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2fonsi%2fginkgo%2fv2/v2.19.0/v2.20.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | require | minor |
| golang.org/x/exp | `8a7402a` -> `0cdaa3a` | [![age](https://developer.mend.io/api/mc/badges/age/go/golang.org%2fx%2fexp/v0.0.0-20240808152545-0cdaa3abc0fa?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/go/golang.org%2fx%2fexp/v0.0.0-20240808152545-0cdaa3abc0fa?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/go/golang.org%2fx%2fexp/v0.0.0-20240719175910-8a7402abbf56/v0.0.0-20240808152545-0cdaa3abc0fa?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/go/golang.org%2fx%2fexp/v0.0.0-20240719175910-8a7402abbf56/v0.0.0-20240808152545-0cdaa3abc0fa?slim=true)](https://docs.renovatebot.com/merge-confidence/) | require | digest |

---

### Release Notes

<details>
<summary>onsi/ginkgo (github.com/onsi/ginkgo/v2)</summary>

### [`v2.20.0`](https://togithub.com/onsi/ginkgo/releases/tag/v2.20.0)

[Compare Source](https://togithub.com/onsi/ginkgo/compare/v2.19.1...v2.20.0)

#### 2.20.0

##### Features

-   Add buildvcs flag \[[`be5ab95`](https://togithub.com/onsi/ginkgo/commit/be5ab95)]

##### Maintenance

-   Add update-deps to makefile \[[`d303d14`](https://togithub.com/onsi/ginkgo/commit/d303d14)]
-   bump all dependencies \[[`7a50221`](https://togithub.com/onsi/ginkgo/commit/7a50221)]

### [`v2.19.1`](https://togithub.com/onsi/ginkgo/releases/tag/v2.19.1)

[Compare Source](https://togithub.com/onsi/ginkgo/compare/v2.19.0...v2.19.1)

#### 2.19.1

##### Fixes

-   update supported platforms for race conditions \[[`63c8c30`](https://togithub.com/onsi/ginkgo/commit/63c8c30)]
-   \[build] Allow custom name for binaries. \[[`ff41e27`](https://togithub.com/onsi/ginkgo/commit/ff41e27)]

##### Maintenance

-   bump gomega \[[`76f4e0c`](https://togithub.com/onsi/ginkgo/commit/76f4e0c)]
-   Bump rexml from 3.2.6 to 3.2.8 in /docs ([#&#8203;1417](https://togithub.com/onsi/ginkgo/issues/1417)) \[[`b69c00d`](https://togithub.com/onsi/ginkgo/commit/b69c00d)]
-   Bump golang.org/x/sys from 0.20.0 to 0.21.0 ([#&#8203;1425](https://togithub.com/onsi/ginkgo/issues/1425)) \[[`f097741`](https://togithub.com/onsi/ginkgo/commit/f097741)]

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://togithub.com/renovatebot/renovate/discussions) if that's undesired.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOC4yMy4yIiwidXBkYXRlZEluVmVyIjoiMzguMjMuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsidHlwZS9taW5vciIsInVwZGF0ZS9nbyJdfQ==-->


syself-bot[bot]: ### ℹ Artifact update notice

##### File name: go.mod

In order to perform the update(s) described in the table above, Renovate ran the `go get` command, which resulted in the following additional change(s):


- 3 additional dependencies were updated


Details:


| **Package**               | **Change**                                                                   |
| :------------------------ | :--------------------------------------------------------------------------- |
| `github.com/google/pprof` | `v0.0.0-20240424215950-a892ee059fd6` -> `v0.0.0-20240727154555-813a5fbdbec8` |
| `golang.org/x/net`        | `v0.27.0` -> `v0.28.0`                                                       |
| `golang.org/x/tools`      | `v0.23.0` -> `v0.24.0`                                                       |

Patch:
diff --git a/api/v1beta1/hetznerbaremetalhost_types.go b/api/v1beta1/hetznerbaremetalhost_types.go
index 47be9682..c86dbad9 100644
--- a/api/v1beta1/hetznerbaremetalhost_types.go
+++ b/api/v1beta1/hetznerbaremetalhost_types.go
@@ -22,10 +22,12 @@ import (
 	"encoding/json"
 	"fmt"
 	"strings"
+	"time"
 
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
+	"sigs.k8s.io/cluster-api/util/record"
 )
 
 const (
@@ -547,6 +549,14 @@ func (host *HetznerBareMetalHost) SetError(errType ErrorType, errMessage string)
 	}
 	host.Spec.Status.ErrorType = errType
 	host.Spec.Status.ErrorMessage = errMessage
+	if errType == PermanentError {
+		if host.Annotations == nil {
+			host.Annotations = make(map[string]string, 1)
+		}
+		host.Annotations[PermanentErrorAnnotation] = time.Now().Format(time.RFC3339)
+		record.Warnf(host, "PermanentErrorSet", "Remove annotation %q, if you want the controller to use the hbmh again.",
+			PermanentErrorAnnotation)
+	}
 }
 
 // ClearError removes the error on the host and resets the error count to 0.
diff --git a/api/v1beta1/hetznerbaremetalremediation_types.go b/api/v1beta1/hetznerbaremetalremediation_types.go
index 527df7c7..a1829588 100644
--- a/api/v1beta1/hetznerbaremetalremediation_types.go
+++ b/api/v1beta1/hetznerbaremetalremediation_types.go
@@ -27,6 +27,11 @@ const (
 
 	// RebootAnnotation indicates that a bare metal host object should be rebooted.
 	RebootAnnotation = "reboot.hetznerbaremetalhost.infrastructure.cluster.x-k8s.io"
+
+	// PermanentErrorAnnotation indicates that the bare metal host has an error which needs to be resolved manually.
+	// After the permanent error the annotation got removed (usually by a human), the controller removes
+	// ErrorType, ErrorCount and ErrorMessages, so that the hbmh will be usable again.
+	PermanentErrorAnnotation = "error.hetznerbaremetalhost.infrastructure.cluster.x-k8s.io"
 )
 
 // HetznerBareMetalRemediationSpec defines the desired state of HetznerBareMetalRemediation.
diff --git a/controllers/csr_controller.go b/controllers/csr_controller.go
index cb80895f..4a57d829 100644
--- a/controllers/csr_controller.go
+++ b/controllers/csr_controller.go
@@ -175,7 +175,7 @@ func (r *GuestCSRReconciler) Reconcile(ctx context.Context, req reconcile.Reques
 			certificateSigningRequest.Spec.Username, err)
 	}
 
-	record.Event(certificateSigningRequest, "CSRApproved", "approved csr")
+	record.Eventf(certificateSigningRequest, "CSRApproved", "approved csr for %q", certificateSigningRequest.Spec.Username)
 	return reconcile.Result{}, nil
 }
 
diff --git a/controllers/hetznerbaremetalhost_controller.go b/controllers/hetznerbaremetalhost_controller.go
index 2f45b95e..be069bc2 100644
--- a/controllers/hetznerbaremetalhost_controller.go
+++ b/controllers/hetznerbaremetalhost_controller.go
@@ -97,6 +97,18 @@ func (r *HetznerBareMetalHostReconciler) Reconcile(ctx context.Context, req ctrl
 		return ctrl.Result{Requeue: true}, nil
 	}
 
+	// Remove permanent error, if the corresponding annotation was removed by the user.
+	removed := removePermanentErrorIfAnnotationIsGone(bmHost)
+	if removed {
+		// The permanent error was removed from Spec.Status.
+		// Save the changes, and then reconcile again.
+		err := r.Update(ctx, bmHost)
+		if err != nil {
+			return reconcile.Result{}, fmt.Errorf("failed to update (after removePermanentErrorIfAnnotationIsGone): %w", err)
+		}
+		return reconcile.Result{Requeue: true}, nil
+	}
+
 	// 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)
@@ -451,3 +463,23 @@ func (r *HetznerBareMetalHostReconciler) SetupWithManager(ctx context.Context, m
 		Owns(&corev1.Secret{}).
 		Complete(r)
 }
+
+func removePermanentErrorIfAnnotationIsGone(bmHost *infrav1.HetznerBareMetalHost,
+) (removed bool) {
+	if bmHost.Spec.Status.ErrorType != infrav1.PermanentError {
+		// PermanentError not set. Do nothing.
+		return false
+	}
+	for k := range bmHost.GetAnnotations() {
+		if k == infrav1.PermanentErrorAnnotation {
+			// Annotation was not removed by user. Do nothing.
+			return false
+		}
+	}
+	bmHost.Spec.Status.ErrorType = ""
+	bmHost.Spec.Status.ErrorMessage = ""
+	bmHost.Spec.Status.ErrorCount = 0
+	record.Eventf(bmHost, "PermanentErrorWasRemoved", "The permanent error was removed, because the annotation %q was removed",
+		infrav1.PermanentErrorAnnotation)
+	return true
+}
diff --git a/go.mod b/go.mod
index 00c93d44..47f30345 100644
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,7 @@ require (
 	github.com/go-logr/logr v1.4.2
 	github.com/go-logr/zapr v1.3.0
 	github.com/hetznercloud/hcloud-go/v2 v2.13.0
-	github.com/onsi/ginkgo/v2 v2.19.0
+	github.com/onsi/ginkgo/v2 v2.20.0
 	github.com/onsi/gomega v1.34.1
 	github.com/spf13/pflag v1.0.5
 	github.com/stoewer/go-strcase v1.3.0
@@ -15,7 +15,7 @@ require (
 	github.com/syself/hrobot-go v0.2.5
 	go.uber.org/zap v1.27.0
 	golang.org/x/crypto v0.26.0
-	golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
+	golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa
 	golang.org/x/mod v0.20.0
 	k8s.io/api v0.29.3
 	k8s.io/apimachinery v0.29.3
@@ -71,7 +71,7 @@ require (
 	github.com/google/go-github/v53 v53.2.0 // indirect
 	github.com/google/go-querystring v1.1.0 // indirect
 	github.com/google/gofuzz v1.2.0 // indirect
-	github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect
+	github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect
 	github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 // indirect
 	github.com/google/uuid v1.4.0 // indirect
 	github.com/hashicorp/hcl v1.0.0 // indirect
@@ -115,14 +115,14 @@ require (
 	go.opentelemetry.io/otel/metric v1.22.0 // indirect
 	go.opentelemetry.io/otel/trace v1.22.0 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
-	golang.org/x/net v0.27.0 // indirect
+	golang.org/x/net v0.28.0 // indirect
 	golang.org/x/oauth2 v0.18.0 // indirect
 	golang.org/x/sync v0.8.0 // indirect
 	golang.org/x/sys v0.23.0 // indirect
 	golang.org/x/term v0.23.0 // indirect
 	golang.org/x/text v0.17.0 // indirect
 	golang.org/x/time v0.5.0 // indirect
-	golang.org/x/tools v0.23.0 // indirect
+	golang.org/x/tools v0.24.0 // indirect
 	gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
 	google.golang.org/appengine v1.6.8 // indirect
 	google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect
diff --git a/go.sum b/go.sum
index 92b5f638..b71603c0 100644
--- a/go.sum
+++ b/go.sum
@@ -115,8 +115,8 @@ github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
 github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg=
-github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
+github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k=
+github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
 github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 h1:SJ+NtwL6QaZ21U+IrK7d0gGgpjGGvd2kz+FzTHVzdqI=
 github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2/go.mod h1:Tv1PlzqC9t8wNnpPdctvtSUOPUUg4SHeE6vR1Ir2hmg=
 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -176,8 +176,8 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
 github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
-github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
-github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
+github.com/onsi/ginkgo/v2 v2.20.0 h1:PE84V2mHqoT1sglvHc8ZdQtPcwmvvt29WLEEO3xmdZw=
+github.com/onsi/ginkgo/v2 v2.20.0/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI=
 github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
 github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
 github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
@@ -292,8 +292,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
 golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
 golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
 golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
-golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
-golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
+golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
+golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
@@ -306,8 +306,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
-golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
-golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
+golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
+golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
 golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
 golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -350,8 +350,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
 golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
-golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
+golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
+golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/pkg/services/baremetal/host/host.go b/pkg/services/baremetal/host/host.go
index d31b20b6..6621f377 100644
--- a/pkg/services/baremetal/host/host.go
+++ b/pkg/services/baremetal/host/host.go
@@ -183,6 +183,7 @@ func (s *Service) actionPreparing(_ context.Context) actionResult {
 				clusterv1.ConditionSeverityError,
 				msg,
 			)
+			record.Warnf(s.scope.HetznerBareMetalHost, infrav1.ServerNotFoundReason, msg)
 			s.scope.HetznerBareMetalHost.SetError(infrav1.PermanentError, msg)
 			return actionStop{}
 		}
@@ -263,7 +264,8 @@ func (s *Service) actionPreparing(_ context.Context) actionResult {
 	}
 
 	msg := createRebootEvent(s.scope.HetznerBareMetalHost, rebootType, "Reboot into rescue system.")
-	// we immediately set an error message in the host status to track the reboot we just performed
+	// we immediately set an error message in the host status to track the reboot we just performed.
+	// This is not a real error. Sooner or later we should track the reboots differently.
 	s.scope.HetznerBareMetalHost.SetError(errorType, msg)
 	return actionComplete{} // next: Registering
 }
diff --git a/vendor/github.com/google/pprof/profile/profile.go b/vendor/github.com/google/pprof/profile/profile.go
index 62df80a5..5551eb0b 100644
--- a/vendor/github.com/google/pprof/profile/profile.go
+++ b/vendor/github.com/google/pprof/profile/profile.go
@@ -847,7 +847,7 @@ func (p *Profile) HasFileLines() bool {
 // "[vdso]", [vsyscall]" and some others, see the code.
 func (m *Mapping) Unsymbolizable() bool {
 	name := filepath.Base(m.File)
-	return strings.HasPrefix(name, "[") || strings.HasPrefix(name, "linux-vdso") || strings.HasPrefix(m.File, "/dev/dri/")
+	return strings.HasPrefix(name, "[") || strings.HasPrefix(name, "linux-vdso") || strings.HasPrefix(m.File, "/dev/dri/") || m.File == "//anon"
 }
 
 // Copy makes a fully independent copy of a profile.
diff --git a/vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md b/vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md
index 76577dc7..56fa8d24 100644
--- a/vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md
+++ b/vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md
@@ -1,3 +1,23 @@
+## 2.20.0
+
+### Features
+- Add buildvcs flag [be5ab95]
+
+### Maintenance
+- Add update-deps to makefile [d303d14]
+- bump all dependencies [7a50221]
+
+## 2.19.1
+
+### Fixes
+- update supported platforms for race conditions [63c8c30]
+- [build] Allow custom name for binaries. [ff41e27]
+
+### Maintenance
+- bump gomega [76f4e0c]
+- Bump rexml from 3.2.6 to 3.2.8 in /docs (#1417) [b69c00d]
+- Bump golang.org/x/sys from 0.20.0 to 0.21.0 (#1425) [f097741]
+
 ## 2.19.0
 
 ### Features
diff --git a/vendor/github.com/onsi/ginkgo/v2/Makefile b/vendor/github.com/onsi/ginkgo/v2/Makefile
index cb099aff..06dff97c 100644
--- a/vendor/github.com/onsi/ginkgo/v2/Makefile
+++ b/vendor/github.com/onsi/ginkgo/v2/Makefile
@@ -4,8 +4,13 @@ all:  vet test
 
 .PHONY: test
 test:
-	go run github.com/onsi/ginkgo/v2/ginkgo -r -p
+	go run github.com/onsi/ginkgo/v2/ginkgo -r -p -randomize-all -keep-going
 
 .PHONY: vet
 vet:
 	go vet ./...
+
+.PHONY: update-deps
+update-deps:
+	go get -u ./...
+	go mod tidy
\ No newline at end of file
diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/build/build_command.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/build/build_command.go
index 5db5d1a7..fd172608 100644
--- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/build/build_command.go
+++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/build/build_command.go
@@ -2,6 +2,8 @@ package build
 
 import (
 	"fmt"
+	"os"
+	"path"
 
 	"github.com/onsi/ginkgo/v2/ginkgo/command"
 	"github.com/onsi/ginkgo/v2/ginkgo/internal"
@@ -53,7 +55,18 @@ func buildSpecs(args []string, cliConfig types.CLIConfig, goFlagsConfig types.Go
 		if suite.State.Is(internal.TestSuiteStateFailedToCompile) {
 			fmt.Println(suite.CompilationError.Error())
 		} else {
-			fmt.Printf("Compiled %s.test\n", suite.PackageName)
+			if len(goFlagsConfig.O) == 0 {
+				goFlagsConfig.O = path.Join(suite.Path, suite.PackageName+".test")
+			} else {
+				stat, err := os.Stat(goFlagsConfig.O)
+				if err != nil {
+					panic(err)
+				}
+				if stat.IsDir() {
+					goFlagsConfig.O += "/" + suite.PackageName + ".test"
+				}
+			}
+			fmt.Printf("Compiled %s\n", goFlagsConfig.O)
 		}
 	}
 
diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/compile.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/compile.go
index 86da7340..48827cc5 100644
--- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/compile.go
+++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/compile.go
@@ -25,6 +25,18 @@ func CompileSuite(suite TestSuite, goFlagsConfig types.GoFlagsConfig) TestSuite
 		return suite
 	}
 
+	if len(goFlagsConfig.O) > 0 {
+		userDefinedPath, err := filepath.Abs(goFlagsConfig.O)
+		if err != nil {
+			suite.State = TestSuiteStateFailedToCompile
+			suite.CompilationError = fmt.Errorf("Failed to compute compilation target path %s:\n%s", goFlagsConfig.O, err.Error())
+			return suite
+		}
+		path = userDefinedPath
+	}
+
+	goFlagsConfig.O = path
+
 	ginkgoInvocationPath, _ := os.Getwd()
 	ginkgoInvocationPath, _ = filepath.Abs(ginkgoInvocationPath)
 	packagePath := suite.AbsPath()
@@ -34,7 +46,7 @@ func CompileSuite(suite TestSuite, goFlagsConfig types.GoFlagsConfig) TestSuite
 		suite.CompilationError = fmt.Errorf("Failed to get relative path from package to the current working directory:\n%s", err.Error())
 		return suite
 	}
-	args, err := types.GenerateGoTestCompileArgs(goFlagsConfig, path, "./", pathToInvocationPath)
+	args, err := types.GenerateGoTestCompileArgs(goFlagsConfig, "./", pathToInvocationPath)
 	if err != nil {
 		suite.State = TestSuiteStateFailedToCompile
 		suite.CompilationError = fmt.Errorf("Failed to generate go test compile flags:\n%s", err.Error())
diff --git a/vendor/github.com/onsi/ginkgo/v2/types/config.go b/vendor/github.com/onsi/ginkgo/v2/types/config.go
index 66463cf5..97a049e0 100644
--- a/vendor/github.com/onsi/ginkgo/v2/types/config.go
+++ b/vendor/github.com/onsi/ginkgo/v2/types/config.go
@@ -202,6 +202,7 @@ type GoFlagsConfig struct {
 	A             bool
 	ASMFlags      string
 	BuildMode     string
+	BuildVCS      bool
 	Compiler      string
 	GCCGoFlags    string
 	GCFlags       string
@@ -219,6 +220,7 @@ type GoFlagsConfig struct {
 	ToolExec      string
 	Work          bool
 	X             bool
+	O             string
 }
 
 func NewDefaultGoFlagsConfig() GoFlagsConfig {
@@ -511,7 +513,7 @@ var GinkgoCLIWatchFlags = GinkgoFlags{
 // GoBuildFlags provides flags for the Ginkgo CLI build, run, and watch commands that capture go's build-time flags.  These are passed to go test -c by the ginkgo CLI
 var GoBuildFlags = GinkgoFlags{
 	{KeyPath: "Go.Race", Name: "race", SectionKey: "code-and-coverage-analysis",
-		Usage: "enable data race detection. Supported only on linux/amd64, freebsd/amd64, darwin/amd64, windows/amd64, linux/ppc64le and linux/arm64 (only for 48-bit VMA)."},
+		Usage: "enable data race detection. Supported on linux/amd64, linux/ppc64le, linux/arm64, linux/s390x, freebsd/amd64, netbsd/amd64, darwin/amd64, darwin/arm64, and windows/amd64."},
 	{KeyPath: "Go.Vet", Name: "vet", UsageArgument: "list", SectionKey: "code-and-coverage-analysis",
 		Usage: `Configure the invocation of "go vet" during "go test" to use the comma-separated list of vet checks.  If list is empty, "go test" runs "go vet" with a curated list of checks believed to be always worth addressing.  If list is "off", "go test" does not run "go vet" at all.  Available checks can be found by running 'go doc cmd/vet'`},
 	{KeyPath: "Go.Cover", Name: "cover", SectionKey: "code-and-coverage-analysis",
@@ -527,6 +529,8 @@ var GoBuildFlags = GinkgoFlags{
 		Usage: "arguments to pass on each go tool asm invocation."},
 	{KeyPath: "Go.BuildMode", Name: "buildmode", UsageArgument: "mode", SectionKey: "go-build",
 		Usage: "build mode to use. See 'go help buildmode' for more."},
+	{KeyPath: "Go.BuildVCS", Name: "buildvcs", SectionKey: "go-build",
+		Usage: "adds version control information."},
 	{KeyPath: "Go.Compiler", Name: "compiler", UsageArgument: "name", SectionKey: "go-build",
 		Usage: "name of compiler to use, as in runtime.Compiler (gccgo or gc)."},
 	{KeyPath: "Go.GCCGoFlags", Name: "gccgoflags", UsageArgument: "'[pattern=]arg list'", SectionKey: "go-build",
@@ -561,6 +565,8 @@ var GoBuildFlags = GinkgoFlags{
 		Usage: "print the name of the temporary work directory and do not delete it when exiting."},
 	{KeyPath: "Go.X", Name: "x", SectionKey: "go-build",
 		Usage: "print the commands."},
+	{KeyPath: "Go.O", Name: "o", SectionKey: "go-build",
+		Usage: "output binary path (including name)."},
 }
 
 // GoRunFlags provides flags for the Ginkgo CLI  run, and watch commands that capture go's run-time flags.  These are passed to the compiled test binary by the ginkgo CLI
@@ -614,7 +620,7 @@ func VetAndInitializeCLIAndGoConfig(cliConfig CLIConfig, goFlagsConfig GoFlagsCo
 }
 
 // GenerateGoTestCompileArgs is used by the Ginkgo CLI to generate command line arguments to pass to the go test -c command when compiling the test
-func GenerateGoTestCompileArgs(goFlagsConfig GoFlagsConfig, destination string, packageToBuild string, pathToInvocationPath string) ([]string, error) {
+func GenerateGoTestCompileArgs(goFlagsConfig GoFlagsConfig, packageToBuild string, pathToInvocationPath string) ([]string, error) {
 	// if the user has set the CoverProfile run-time flag make sure to set the build-time cover flag to make sure
 	// the built test binary can generate a coverprofile
 	if goFlagsConfig.CoverProfile != "" {
@@ -637,7 +643,7 @@ func GenerateGoTestCompileArgs(goFlagsConfig GoFlagsConfig, destination string,
 		goFlagsConfig.CoverPkg = strings.Join(adjustedCoverPkgs, ",")
 	}
 
-	args := []string{"test", "-c", "-o", destination, packageToBuild}
+	args := []string{"test", "-c", packageToBuild}
 	goArgs, err := GenerateFlagArgs(
 		GoBuildFlags,
 		map[string]interface{}{
diff --git a/vendor/github.com/onsi/ginkgo/v2/types/version.go b/vendor/github.com/onsi/ginkgo/v2/types/version.go
index acab0349..c6af20b6 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.19.0"
+const VERSION = "2.20.0"
diff --git a/vendor/golang.org/x/net/LICENSE b/vendor/golang.org/x/net/LICENSE
index 6a66aea5..2a7cf70d 100644
--- a/vendor/golang.org/x/net/LICENSE
+++ b/vendor/golang.org/x/net/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2009 The Go Authors. All rights reserved.
+Copyright 2009 The Go Authors.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
 copyright notice, this list of conditions and the following disclaimer
 in the documentation and/or other materials provided with the
 distribution.
-   * Neither the name of Google Inc. nor the names of its
+   * Neither the name of Google LLC nor the names of its
 contributors may be used to endorse or promote products derived from
 this software without specific prior written permission.
 
diff --git a/vendor/golang.org/x/tools/LICENSE b/vendor/golang.org/x/tools/LICENSE
index 6a66aea5..2a7cf70d 100644
--- a/vendor/golang.org/x/tools/LICENSE
+++ b/vendor/golang.org/x/tools/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2009 The Go Authors. All rights reserved.
+Copyright 2009 The Go Authors.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
 copyright notice, this list of conditions and the following disclaimer
 in the documentation and/or other materials provided with the
 distribution.
-   * Neither the name of Google Inc. nor the names of its
+   * Neither the name of Google LLC nor the names of its
 contributors may be used to endorse or promote products derived from
 this software without specific prior written permission.
 
diff --git a/vendor/modules.txt b/vendor/modules.txt
index d129f98c..3c8a1b5c 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -224,7 +224,7 @@ github.com/google/go-querystring/query
 ## explicit; go 1.12
 github.com/google/gofuzz
 github.com/google/gofuzz/bytesource
-# github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6
+# github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8
 ## explicit; go 1.19
 github.com/google/pprof/profile
 # github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2
@@ -295,7 +295,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.19.0
+# github.com/onsi/ginkgo/v2 v2.20.0
 ## explicit; go 1.20
 github.com/onsi/ginkgo/v2
 github.com/onsi/ginkgo/v2/config
@@ -487,7 +487,7 @@ golang.org/x/crypto/scrypt
 golang.org/x/crypto/sha3
 golang.org/x/crypto/ssh
 golang.org/x/crypto/ssh/internal/bcrypt_pbkdf
-# golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
+# golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa
 ## explicit; go 1.20
 golang.org/x/exp/constraints
 golang.org/x/exp/maps
@@ -501,7 +501,7 @@ golang.org/x/mod/internal/lazyregexp
 golang.org/x/mod/modfile
 golang.org/x/mod/module
 golang.org/x/mod/semver
-# golang.org/x/net v0.27.0
+# golang.org/x/net v0.28.0
 ## explicit; go 1.18
 golang.org/x/net/context
 golang.org/x/net/html
@@ -562,7 +562,7 @@ golang.org/x/text/width
 # golang.org/x/time v0.5.0
 ## explicit; go 1.18
 golang.org/x/time/rate
-# golang.org/x/tools v0.23.0
+# golang.org/x/tools v0.24.0
 ## explicit; go 1.19
 golang.org/x/tools/cover
 golang.org/x/tools/go/ast/inspector


Test patch:
diff --git a/api/v1beta1/hetznerbaremetalhost_types_test.go b/api/v1beta1/hetznerbaremetalhost_types_test.go
index 1bdff132..9b7d205f 100644
--- a/api/v1beta1/hetznerbaremetalhost_types_test.go
+++ b/api/v1beta1/hetznerbaremetalhost_types_test.go
@@ -17,9 +17,15 @@ limitations under the License.
 package v1beta1
 
 import (
+	"cmp"
+	"slices"
+	"testing"
+
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
+	"github.com/stretchr/testify/require"
 	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
 var _ = Describe("Test update secret status", func() {
@@ -458,3 +464,36 @@ var _ = Describe("Test ClearRebootAnnotations", func() {
 		}),
 	)
 })
+
+func mapKeys[K cmp.Ordered, V any](m map[K]V) []K {
+	ret := make([]K, 0, len(m))
+	for k := range m {
+		ret = append(ret, k)
+	}
+	slices.Sort(ret)
+	return ret
+}
+
+func TestHetznerBareMetalHost_SetError(t *testing.T) {
+	// A PermanentError should add the PermanentErrorAnnotation
+	host := HetznerBareMetalHost{
+		ObjectMeta: metav1.ObjectMeta{
+			Annotations: map[string]string{
+				"other-annotation": "some value",
+			},
+		},
+	}
+	host.SetError(PermanentError, "some error")
+	require.Equal(t, []string{PermanentErrorAnnotation, "other-annotation"}, mapKeys(host.Annotations))
+
+	// Other errors should not add the PermanentErrorAnnotation
+	host = HetznerBareMetalHost{
+		ObjectMeta: metav1.ObjectMeta{
+			Annotations: map[string]string{
+				"other-annotation": "some value",
+			},
+		},
+	}
+	host.SetError(ProvisioningError, "some error")
+	require.Equal(t, []string{"other-annotation"}, mapKeys(host.Annotations))
+}
diff --git a/controllers/hetznerbaremetalhost_controller_test.go b/controllers/hetznerbaremetalhost_controller_test.go
index 2d9e897b..326e54f5 100644
--- a/controllers/hetznerbaremetalhost_controller_test.go
+++ b/controllers/hetznerbaremetalhost_controller_test.go
@@ -17,11 +17,13 @@ limitations under the License.
 package controllers
 
 import (
+	"testing"
 	"time"
 
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
 	"github.com/stretchr/testify/mock"
+	"github.com/stretchr/testify/require"
 	"github.com/syself/hrobot-go/models"
 	corev1 "k8s.io/api/core/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -899,3 +901,70 @@ name="eth0" model="Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express
 	sshClient.On("GetInstallImageState").Return(sshclient.InstallImageStateFinished, nil)
 	sshClient.On("GetResultOfInstallImage").Return(hostpkg.PostInstallScriptFinished, nil)
 }
+
+func Test_removePermanentErrorIfAnnotationIsGone(t *testing.T) {
+	// PermanentError with annotation --> Error should not get removed
+	bmHost := infrav1.HetznerBareMetalHost{
+		TypeMeta: metav1.TypeMeta{},
+		ObjectMeta: metav1.ObjectMeta{
+			Annotations: map[string]string{
+				infrav1.PermanentErrorAnnotation: "",
+			},
+		},
+		Spec: infrav1.HetznerBareMetalHostSpec{
+			Status: infrav1.ControllerGeneratedStatus{
+				ErrorType:    infrav1.PermanentError,
+				ErrorCount:   1,
+				ErrorMessage: "my err",
+			},
+		},
+	}
+	removed := removePermanentErrorIfAnnotationIsGone(&bmHost)
+	require.False(t, removed)
+	require.NotEmpty(t, bmHost.Spec.Status.ErrorType)
+	require.NotEmpty(t, bmHost.Spec.Status.ErrorCount)
+	require.NotEmpty(t, bmHost.Spec.Status.ErrorMessage)
+
+	// PermanentError without annotation --> Error should get removed
+	bmHost = infrav1.HetznerBareMetalHost{
+		TypeMeta: metav1.TypeMeta{},
+		ObjectMeta: metav1.ObjectMeta{
+			Annotations: map[string]string{
+				"other-annotation": "some value",
+			},
+		},
+		Spec: infrav1.HetznerBareMetalHostSpec{
+			Status: infrav1.ControllerGeneratedStatus{
+				ErrorType:    infrav1.PermanentError,
+				ErrorCount:   1,
+				ErrorMessage: "my err",
+			},
+		},
+	}
+	removed = removePermanentErrorIfAnnotationIsGone(&bmHost)
+	require.True(t, removed)
+	require.Empty(t, bmHost.Spec.Status.ErrorType)
+	require.Empty(t, bmHost.Spec.Status.ErrorCount)
+	require.Empty(t, bmHost.Spec.Status.ErrorMessage)
+	require.Equal(t, map[string]string{"other-annotation": "some value"}, bmHost.Annotations)
+
+	// Other Error without annotation --> Error should not get removed
+	bmHost = infrav1.HetznerBareMetalHost{
+		TypeMeta: metav1.TypeMeta{},
+		ObjectMeta: metav1.ObjectMeta{
+			Annotations: map[string]string{},
+		},
+		Spec: infrav1.HetznerBareMetalHostSpec{
+			Status: infrav1.ControllerGeneratedStatus{
+				ErrorType:    infrav1.ProvisioningError,
+				ErrorCount:   1,
+				ErrorMessage: "my err",
+			},
+		},
+	}
+	removed = removePermanentErrorIfAnnotationIsGone(&bmHost)
+	require.False(t, removed)
+	require.NotEmpty(t, bmHost.Spec.Status.ErrorType)
+	require.NotEmpty(t, bmHost.Spec.Status.ErrorCount)
+	require.NotEmpty(t, bmHost.Spec.Status.ErrorMessage)
+}
diff --git a/test/e2e/caph.go b/test/e2e/caph.go
index 64e2f304..b5bec6e0 100644
--- a/test/e2e/caph.go
+++ b/test/e2e/caph.go
@@ -46,7 +46,7 @@ type CaphClusterDeploymentSpecInput struct {
 // CaphClusterDeploymentSpec implements a test that verifies that MachineDeployment rolling updates are successful.
 func CaphClusterDeploymentSpec(ctx context.Context, inputGetter func() CaphClusterDeploymentSpecInput) {
 	var (
-		specName         = "caph"
+		specName         = "ci" + os.Getenv("GITHUB_RUN_ID")
 		input            CaphClusterDeploymentSpecInput
 		namespace        *corev1.Namespace
 		cancelWatches    context.CancelFunc
@@ -60,7 +60,7 @@ func CaphClusterDeploymentSpec(ctx context.Context, inputGetter func() CaphClust
 		gomega.Expect(input.E2EConfig).ToNot(gomega.BeNil(), "Invalid argument. input.E2EConfig can't be nil when calling %s spec", specName)
 		gomega.Expect(input.ClusterctlConfigPath).To(gomega.BeAnExistingFile(), "Invalid argument. input.ClusterctlConfigPath must be an existing file when calling %s spec", specName)
 		gomega.Expect(input.BootstrapClusterProxy).ToNot(gomega.BeNil(), "Invalid argument. input.BootstrapClusterProxy can't be nil when calling %s spec", specName)
-		gomega.Expect(os.MkdirAll(input.ArtifactFolder, 0750)).To(gomega.Succeed(), "Invalid argument. input.ArtifactFolder can't be created for %s spec", specName)
+		gomega.Expect(os.MkdirAll(input.ArtifactFolder, 0o750)).To(gomega.Succeed(), "Invalid argument. input.ArtifactFolder can't be created for %s spec", specName)
 		gomega.Expect(input.E2EConfig.Variables).To(gomega.HaveKey(KubernetesVersion))
 		gomega.Expect(input.E2EConfig.Variables).To(HaveValidVersion(input.E2EConfig.GetVariable(KubernetesVersion)))