Skip to content

Commit c3b5748

Browse files
authored
🌱 HCloudMachineType: allow all values. (#1693)
* 🌱 HCloudMachineType: allow all values. The list of valid machine types gets changed by Hetzner from time to time. CAPH no longer validates this string. It is up to you to use a valid type. Not all types are available in all locations. Additionally Remediation was fixed if providerID was nil.
1 parent 4bc8057 commit c3b5748

File tree

7 files changed

+114
-114
lines changed

7 files changed

+114
-114
lines changed

api/v1beta1/hcloudmachine_types.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,18 @@ type HCloudMachineSpec struct {
3939
// +optional
4040
ProviderID *string `json:"providerID,omitempty"`
4141

42-
// Type is the HCloud Machine Type for this machine. It defines the desired server type of server in Hetzner's Cloud API. Example: cpx11.
43-
// +kubebuilder:validation:Enum=cpx11;cx21;cpx21;cx31;cpx31;cx41;cpx41;cx51;cpx51;ccx11;ccx12;ccx13;ccx21;ccx22;ccx23;ccx31;ccx32;ccx33;ccx41;ccx42;ccx43;ccx51;ccx52;ccx53;ccx62;ccx63;cax11;cax21;cax31;cax41;cx22;cx32;cx42;cx52
42+
// Type is the HCloud Machine Type for this machine. It defines the desired server type of
43+
// server in Hetzner's Cloud API. You can use the hcloud CLI to get server names (`hcloud
44+
// server-type list`) or on https://www.hetzner.com/cloud
45+
//
46+
// The types follow this pattern: cxNV (shared, cheap), cpxNV (shared, performance), ccxNV
47+
// (dedicated), caxNV (ARM)
48+
//
49+
// N is a number, and V is the version of this machine type. Example: cpx32.
50+
//
51+
// The list of valid machine types gets changed by Hetzner from time to time. CAPH no longer
52+
// validates this string. It is up to you to use a valid type. Not all types are available in all
53+
// locations.
4454
Type HCloudMachineType `json:"type"`
4555

4656
// ImageName is the reference to the Machine Image from which to create the machine instance.

config/crd/bases/infrastructure.cluster.x-k8s.io_hcloudmachines.yaml

Lines changed: 13 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -140,44 +140,19 @@ spec:
140140
type: object
141141
type: array
142142
type:
143-
description: 'Type is the HCloud Machine Type for this machine. It
144-
defines the desired server type of server in Hetzner''s Cloud API.
145-
Example: cpx11.'
146-
enum:
147-
- cpx11
148-
- cx21
149-
- cpx21
150-
- cx31
151-
- cpx31
152-
- cx41
153-
- cpx41
154-
- cx51
155-
- cpx51
156-
- ccx11
157-
- ccx12
158-
- ccx13
159-
- ccx21
160-
- ccx22
161-
- ccx23
162-
- ccx31
163-
- ccx32
164-
- ccx33
165-
- ccx41
166-
- ccx42
167-
- ccx43
168-
- ccx51
169-
- ccx52
170-
- ccx53
171-
- ccx62
172-
- ccx63
173-
- cax11
174-
- cax21
175-
- cax31
176-
- cax41
177-
- cx22
178-
- cx32
179-
- cx42
180-
- cx52
143+
description: |-
144+
Type is the HCloud Machine Type for this machine. It defines the desired server type of
145+
server in Hetzner's Cloud API. You can use the hcloud CLI to get server names (`hcloud
146+
server-type list`) or on https://www.hetzner.com/cloud
147+
148+
The types follow this pattern: cxNV (shared, cheap), cpxNV (shared, performance), ccxNV
149+
(dedicated), caxNV (ARM)
150+
151+
N is a number, and V is the version of this machine type. Example: cpx32.
152+
153+
The list of valid machine types gets changed by Hetzner from time to time. CAPH no longer
154+
validates this string. It is up to you to use a valid type. Not all types are available in all
155+
locations.
181156
type: string
182157
required:
183158
- type

config/crd/bases/infrastructure.cluster.x-k8s.io_hcloudmachinetemplates.yaml

Lines changed: 13 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -167,44 +167,19 @@ spec:
167167
type: object
168168
type: array
169169
type:
170-
description: 'Type is the HCloud Machine Type for this machine.
171-
It defines the desired server type of server in Hetzner''s
172-
Cloud API. Example: cpx11.'
173-
enum:
174-
- cpx11
175-
- cx21
176-
- cpx21
177-
- cx31
178-
- cpx31
179-
- cx41
180-
- cpx41
181-
- cx51
182-
- cpx51
183-
- ccx11
184-
- ccx12
185-
- ccx13
186-
- ccx21
187-
- ccx22
188-
- ccx23
189-
- ccx31
190-
- ccx32
191-
- ccx33
192-
- ccx41
193-
- ccx42
194-
- ccx43
195-
- ccx51
196-
- ccx52
197-
- ccx53
198-
- ccx62
199-
- ccx63
200-
- cax11
201-
- cax21
202-
- cax31
203-
- cax41
204-
- cx22
205-
- cx32
206-
- cx42
207-
- cx52
170+
description: |-
171+
Type is the HCloud Machine Type for this machine. It defines the desired server type of
172+
server in Hetzner's Cloud API. You can use the hcloud CLI to get server names (`hcloud
173+
server-type list`) or on https://www.hetzner.com/cloud
174+
175+
The types follow this pattern: cxNV (shared, cheap), cpxNV (shared, performance), ccxNV
176+
(dedicated), caxNV (ARM)
177+
178+
N is a number, and V is the version of this machine type. Example: cpx32.
179+
180+
The list of valid machine types gets changed by Hetzner from time to time. CAPH no longer
181+
validates this string. It is up to you to use a valid type. Not all types are available in all
182+
locations.
208183
type: string
209184
required:
210185
- type

controllers/hcloudmachine_controller_test.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -826,11 +826,6 @@ var _ = Describe("HCloudMachine validation", func() {
826826
Expect(testEnv.Cleanup(ctx, testNs, hcloudMachine)).To(Succeed())
827827
})
828828

829-
It("should fail with wrong type", func() {
830-
hcloudMachine.Spec.Type = "wrong-type"
831-
Expect(testEnv.Create(ctx, hcloudMachine)).ToNot(Succeed())
832-
})
833-
834829
It("should fail without imageName", func() {
835830
hcloudMachine.Spec.ImageName = ""
836831
Expect(testEnv.Create(ctx, hcloudMachine)).ToNot(Succeed())

controllers/hcloudremediation_controller_test.go

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package controllers
1818

1919
import (
20+
"fmt"
2021
"time"
2122

2223
"github.com/hetznercloud/hcloud-go/v2/hcloud"
@@ -205,14 +206,16 @@ var _ = Describe("HCloudRemediationReconciler", func() {
205206

206207
It("checks that no remediation is tried if HCloud server does not exist anymore", func() {
207208
By("ensuring if hcloudMachine is provisioned")
208-
Eventually(func() bool {
209+
Eventually(func() error {
209210
if err := testEnv.Get(ctx, hcloudMachineKey, hcloudMachine); err != nil {
210-
return false
211+
return err
211212
}
212213

213-
testEnv.GetLogger().Info("Status of the hcloudmachine", "status", hcloudMachine.Status)
214-
return hcloudMachine.Status.Ready
215-
}, timeout).Should(BeTrue())
214+
if !hcloudMachine.Status.Ready {
215+
return fmt.Errorf("hcloudMachine.Status.Ready is not true (yet)")
216+
}
217+
return nil
218+
}, timeout).ShouldNot(HaveOccurred())
216219

217220
By("deleting the server associated with the hcloudMachine")
218221
providerID, err := hcloudutil.ServerIDFromProviderID(hcloudMachine.Spec.ProviderID)
@@ -235,28 +238,60 @@ var _ = Describe("HCloudRemediationReconciler", func() {
235238
})
236239

237240
It("checks that, under normal conditions, a reboot is carried out and retryCount and lastRemediated are set", func() {
241+
// Wait until machine has a ProviderID
242+
Eventually(func() error {
243+
err := testEnv.Client.Get(ctx, hcloudMachineKey, hcloudMachine)
244+
if err != nil {
245+
return err
246+
}
247+
if hcloudMachine.Spec.ProviderID == nil {
248+
return fmt.Errorf("hcloudMachine.Spec.ProviderID is still nil")
249+
}
250+
return nil
251+
}).NotTo(HaveOccurred())
252+
238253
Expect(testEnv.Create(ctx, hcloudRemediation)).To(Succeed())
239254

240-
Eventually(func() bool {
255+
Eventually(func() error {
241256
if err := testEnv.Get(ctx, hcloudRemediationkey, hcloudRemediation); err != nil {
242-
return false
257+
return err
243258
}
244259

245-
return hcloudRemediation.Status.LastRemediated != nil && hcloudRemediation.Status.RetryCount == 1
246-
}, timeout).Should(BeTrue())
260+
if hcloudRemediation.Status.LastRemediated == nil {
261+
return fmt.Errorf("hcloudRemediation.Status.LastRemediated == nil")
262+
}
263+
if hcloudRemediation.Status.RetryCount != 1 {
264+
return fmt.Errorf("hcloudRemediation.Status.RetryCount is %d", hcloudRemediation.Status.RetryCount)
265+
}
266+
return nil
267+
}, timeout).ShouldNot(HaveOccurred())
247268
})
248269

249270
It("checks if PhaseWaiting is set when retryLimit is reached", func() {
271+
// Wait until machine has a ProviderID
272+
Eventually(func() error {
273+
err := testEnv.Client.Get(ctx, hcloudMachineKey, hcloudMachine)
274+
if err != nil {
275+
return err
276+
}
277+
if hcloudMachine.Spec.ProviderID == nil {
278+
return fmt.Errorf("hcloudMachine.Spec.ProviderID is still nil")
279+
}
280+
return nil
281+
}).NotTo(HaveOccurred())
282+
283+
hcloudRemediation.Status.RetryCount = hcloudRemediation.Spec.Strategy.RetryLimit
250284
Expect(testEnv.Create(ctx, hcloudRemediation)).To(Succeed())
251285

252-
Eventually(func() bool {
286+
Eventually(func() error {
253287
if err := testEnv.Get(ctx, hcloudRemediationkey, hcloudRemediation); err != nil {
254-
return false
288+
return err
255289
}
256-
257-
testEnv.GetLogger().Info("status of hcloudRemediation", "status", hcloudRemediation.Status.Phase)
258-
return hcloudRemediation.Status.Phase == infrav1.PhaseWaiting
259-
}, timeout).Should(BeTrue())
290+
if hcloudRemediation.Status.Phase != infrav1.PhaseWaiting {
291+
return fmt.Errorf("hcloudRemediation.Status.Phase != infrav1.PhaseWaiting (phase is %s)", hcloudRemediation.Status.Phase)
292+
}
293+
return nil
294+
}, timeout).ShouldNot(HaveOccurred())
260295
})
261296

262297
It("should delete machine if retry limit reached and reboot timed out (hcloud)", func() {

pkg/services/hcloud/remediation/remediation.go

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,20 +48,31 @@ func NewService(scope *scope.HCloudRemediationScope) *Service {
4848

4949
// Reconcile implements reconcilement of HCloudRemediation.
5050
func (s *Service) Reconcile(ctx context.Context) (res reconcile.Result, err error) {
51-
server, err := s.findServer(ctx)
52-
if err != nil {
53-
return reconcile.Result{}, fmt.Errorf("failed to find the server of unhealthy machine: %w", err)
51+
var server *hcloud.Server
52+
if s.scope.HCloudMachine.Spec.ProviderID != nil {
53+
server, err = s.findServer(ctx)
54+
if err != nil {
55+
return reconcile.Result{}, fmt.Errorf("failed to find the server of unhealthy machine: %w", err)
56+
}
5457
}
5558

56-
// stop remediation if server does not exist
59+
// stop remediation if server does not exist or ProviderID is nil (in this case the server
60+
// cannot exist).
5761
if server == nil {
5862
s.scope.HCloudRemediation.Status.Phase = infrav1.PhaseDeleting
5963

6064
if err := s.setOwnerRemediatedCondition(ctx); err != nil {
6165
record.Warn(s.scope.HCloudRemediation, "FailedSettingConditionOnMachine", err.Error())
6266
return reconcile.Result{}, fmt.Errorf("failed to set conditions on CAPI machine: %w", err)
6367
}
64-
record.Warn(s.scope.HCloudRemediation, "ExitRemediation", "exit remediation because bare metal server does not exist")
68+
providerID := "nil"
69+
if s.scope.HCloudMachine.Spec.ProviderID != nil {
70+
providerID = *s.scope.HCloudMachine.Spec.ProviderID
71+
}
72+
msg := fmt.Sprintf("exit remediation because hcloud server (providerID=%s) does not exist",
73+
providerID)
74+
s.scope.Logger.Error(nil, msg)
75+
record.Warn(s.scope.HCloudRemediation, "ExitRemediation", msg)
6576
return res, nil
6677
}
6778

pkg/services/hcloud/server/server.go

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -744,7 +744,11 @@ func (s *Service) Delete(ctx context.Context) (res reconcile.Result, err error)
744744

745745
// if no server has been found, then nothing can be deleted
746746
if server == nil {
747-
msg := fmt.Sprintf("Unable to delete HCloud server. Could not find matching server for %s", s.scope.Name())
747+
providerID := "nil"
748+
if s.scope.HCloudMachine.Spec.ProviderID != nil {
749+
providerID = *s.scope.HCloudMachine.Spec.ProviderID
750+
}
751+
msg := fmt.Sprintf("Unable to delete HCloud server. Could not find matching server for %s. ProviderID: %q", s.scope.Name(), providerID)
748752
s.scope.V(1).Info(msg)
749753
record.Warn(s.scope.HCloudMachine, "NoInstanceFound", msg)
750754
return res, nil
@@ -1015,18 +1019,12 @@ func (s *Service) createServer(ctx context.Context, userData []byte, image *hclo
10151019
// RateLimit was reached. Condition and Event got already created.
10161020
return nil, fmt.Errorf("failed to create HCloud server %s: %w", hm.Name, err)
10171021
}
1018-
msg := fmt.Sprintf("failed to create HCloud server %s", hm.Name)
1022+
msg := fmt.Sprintf("failed to create HCloud server %s: %s", hm.Name, err.Error())
10191023
s.scope.Logger.Error(nil, msg)
10201024
// No condition was set yet. Set a general condition to false.
10211025
conditions.MarkFalse(hm, infrav1.ServerCreateSucceededCondition,
1022-
infrav1.ServerCreateFailedReason, clusterv1.ConditionSeverityWarning,
1023-
"%s", msg)
1024-
record.Warnf(hm,
1025-
"FailedCreateHCloudServer",
1026-
"Failed to create HCloud server %s: %s",
1027-
s.scope.Name(),
1028-
err,
1029-
)
1026+
infrav1.ServerCreateFailedReason, clusterv1.ConditionSeverityWarning, "%s", msg)
1027+
record.Warn(hm, "FailedCreateHCloudServer", msg)
10301028
return nil, handleRateLimit(hm, err, "CreateServer", msg)
10311029
}
10321030

@@ -1130,7 +1128,8 @@ func (s *Service) getServerImage(ctx context.Context, imageName string) (*hcloud
11301128
infrav1.ServerCreateSucceededCondition,
11311129
infrav1.ServerTypeNotFoundReason,
11321130
clusterv1.ConditionSeverityError,
1133-
"failed to get server type - nil type",
1131+
"failed to get server type %q",
1132+
string(s.scope.HCloudMachine.Spec.Type),
11341133
)
11351134
return nil, errServerCreateNotPossible
11361135
}

0 commit comments

Comments
 (0)