Skip to content
This repository was archived by the owner on Nov 12, 2025. It is now read-only.

Commit 4b5e1f1

Browse files
authored
Merge pull request #31 from GDATASoftwareAG/rework-to-lan-spec
Rework to lan spec
2 parents cecdb2e + 553084c commit 4b5e1f1

13 files changed

+228
-215
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ The API itself is shared across multiple cloud providers allowing for IONOS Clou
1818
* Choice of Linux distribution between Ubuntu 22.04 and other cloud init distribution using Server Templates based on raw images from [image builder](image_builder).
1919
* Using cloud init for bootstrapping nodes.
2020
* Installs only the minimal components to bootstrap a control plane and workers.
21+
* multi ipv4 lan's (private and public lan)
2122

2223
# Roadmap
2324

@@ -28,7 +29,7 @@ The API itself is shared across multiple cloud providers allowing for IONOS Clou
2829
* failuredomains for control planes
2930
* failuredomains for machinedeployment
3031
* autoscaler integrations example
31-
* multi lan (private and public lan)
32+
* external managed datacenter
3233

3334
---
3435

api/v1alpha1/ionoscloudcluster_types.go

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -51,26 +51,12 @@ const (
5151
// issues with the creation of the datacenter.
5252
DataCenterCreationFailedReason = "DataCenterCreationFailed"
5353

54-
// PublicLanCreatedCondition documents the creation of the Lan
55-
PublicLanCreatedCondition clusterv1.ConditionType = "PublicLanCreated"
54+
// LanCreatedCondition documents the creation of the Lan
55+
LanCreatedCondition clusterv1.ConditionType = "LanCreated"
5656

57-
// PublicLanCreationFailedReason (Severity=Error) documents a controller detecting
57+
// LanCreationFailedReason (Severity=Error) documents a controller detecting
5858
// issues with the creation of the Lan.
59-
PublicLanCreationFailedReason = "PublicLanCreationFailed"
60-
61-
// PrivateLanCreatedCondition documents the creation of the Lan
62-
PrivateLanCreatedCondition clusterv1.ConditionType = "PrivateLanCreated"
63-
64-
// PrivateLanCreationFailedReason (Severity=Error) documents a controller detecting
65-
// issues with the creation of the Lan.
66-
PrivateLanCreationFailedReason = "PrivateLanCreationFailed"
67-
68-
// InternetLanCreatedCondition documents the creation of the Lan
69-
InternetLanCreatedCondition clusterv1.ConditionType = "InternetLanCreated"
70-
71-
// InternetLanCreationFailedReason (Severity=Error) documents a controller detecting
72-
// issues with the creation of the Lan.
73-
InternetLanCreationFailedReason = "InternetLanCreationFailed"
59+
LanCreationFailedReason = "LanCreationFailed"
7460

7561
// LoadBalancerForwardingRuleCreatedCondition documents the creation of the ForwardingRule
7662
LoadBalancerForwardingRuleCreatedCondition clusterv1.ConditionType = "LoadBalancerForwardingRuleCreated"
@@ -102,12 +88,10 @@ type IONOSCloudClusterSpec struct {
10288
IdentityName string `json:"identityName"`
10389
// +optional
10490
ControlPlaneEndpoint clusterv1.APIEndpoint `json:"controlPlaneEndpoint"`
105-
// +optional
10691
// +listType=map
10792
// +listMapKey=name
108-
Lans []IONOSLanSpec `json:"lans,omitempty"`
109-
// +optional
110-
LoadBalancer *IONOSLoadBalancerSpec `json:"loadBalancer,omitempty"`
93+
Lans []IONOSLanSpec `json:"lans"`
94+
LoadBalancer IONOSLoadBalancerSpec `json:"loadBalancer"`
11195

11296
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="DataCenterID is immutable"
11397
DataCenterID string `json:"dataCenterID,omitempty"`

api/v1alpha1/ionoscloudmachine_types.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,15 @@ func (c *IONOSCloudMachine) EnsureNic(spec IONOSNicSpec) {
138138
}
139139
c.Spec.Nics = append(c.Spec.Nics, spec)
140140
}
141+
142+
func (c *IONOSCloudMachine) NicByLan(name string) *IONOSNicSpec {
143+
if name == "" {
144+
return nil
145+
}
146+
for i := range c.Spec.Nics {
147+
if c.Spec.Nics[i].LanRef.Name == name {
148+
return &c.Spec.Nics[i]
149+
}
150+
}
151+
return nil
152+
}

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 1 addition & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ spec:
134134
rule: self == oldSelf
135135
required:
136136
- identityName
137+
- lans
138+
- loadBalancer
137139
- location
138140
type: object
139141
x-kubernetes-validations:

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ spec:
8686
- public
8787
type: object
8888
type: array
89+
x-kubernetes-list-map-keys:
90+
- name
91+
x-kubernetes-list-type: map
8992
loadBalancer:
9093
properties:
9194
id:
@@ -140,6 +143,8 @@ spec:
140143
rule: self == oldSelf
141144
required:
142145
- identityName
146+
- lans
147+
- loadBalancer
143148
- location
144149
type: object
145150
x-kubernetes-validations:

config/samples/cluster_template_ionoscloudcluster.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,15 @@ spec:
88
controlPlaneEndpoint:
99
host: "85.215.201.63"
1010
port: 6443
11+
lans:
12+
- name: private
13+
public: false
14+
- name: public
15+
public: true
16+
- name: internet
17+
public: true
18+
loadBalancer:
19+
listenerLanRef:
20+
name: public
21+
targetLanRef:
22+
name: private

config/samples/infrastructure_v1alpha1_ionoscloudmachinetemplate-control-plane.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,8 @@ spec:
1212
image: "a9152e16-2482-11ee-9eb0-82cf6aa9b8c3"
1313
type: "HDD"
1414
size: "25"
15+
nics:
16+
- lanRef:
17+
name: internet
18+
- lanRef:
19+
name: private

config/samples/infrastructure_v1alpha1_ionoscloudmachinetemplate-worker.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,8 @@ spec:
1212
image: "a9152e16-2482-11ee-9eb0-82cf6aa9b8c3"
1313
type: "HDD"
1414
size: "25"
15+
nics:
16+
- lanRef:
17+
name: internet
18+
- lanRef:
19+
name: private

internal/controller/ionoscloudcluster_controller.go

Lines changed: 35 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,8 @@ func (r *IONOSCloudClusterReconciler) reconcileNormal(ctx *context.ClusterContex
158158
return *result, err
159159
}
160160

161-
if result, err := r.reconcilePrivateLan(ctx); err != nil {
162-
conditions.MarkFalse(ctx.IONOSCloudCluster, v1alpha1.PrivateLanCreatedCondition, v1alpha1.PrivateLanCreationFailedReason, clusterv1.ConditionSeverityError, err.Error())
163-
return *result, err
164-
}
165-
166-
if result, err := r.reconcilePublicLan(ctx); err != nil {
167-
conditions.MarkFalse(ctx.IONOSCloudCluster, v1alpha1.PublicLanCreatedCondition, v1alpha1.PublicLanCreationFailedReason, clusterv1.ConditionSeverityError, err.Error())
161+
if result, err := r.reconcileLan(ctx); err != nil {
162+
conditions.MarkFalse(ctx.IONOSCloudCluster, v1alpha1.LanCreatedCondition, v1alpha1.LanCreationFailedReason, clusterv1.ConditionSeverityError, err.Error())
168163
return *result, err
169164
}
170165

@@ -173,11 +168,6 @@ func (r *IONOSCloudClusterReconciler) reconcileNormal(ctx *context.ClusterContex
173168
return *result, err
174169
}
175170

176-
if result, err := r.reconcileInternet(ctx); err != nil {
177-
conditions.MarkFalse(ctx.IONOSCloudCluster, v1alpha1.InternetLanCreatedCondition, v1alpha1.InternetLanCreationFailedReason, clusterv1.ConditionSeverityError, err.Error())
178-
return *result, err
179-
}
180-
181171
ctx.IONOSCloudCluster.Status.Ready = true
182172

183173
return reconcile.Result{}, nil
@@ -211,107 +201,49 @@ func (r *IONOSCloudClusterReconciler) reconcileDataCenter(ctx *context.ClusterCo
211201
return nil, nil
212202
}
213203

214-
func (r *IONOSCloudClusterReconciler) reconcilePrivateLan(ctx *context.ClusterContext) (*reconcile.Result, error) {
215-
ctx.Logger.Info("Reconciling private Lan")
216-
if ctx.IONOSCloudCluster.Spec.PrivateLanID == nil {
217-
lanID, err := createLan(ctx, false)
218-
if err != nil {
219-
return &reconcile.Result{}, errors.Wrap(err, "error creating private Lan")
204+
func (r *IONOSCloudClusterReconciler) reconcileLan(ctx *context.ClusterContext) (*reconcile.Result, error) {
205+
for i := range ctx.IONOSCloudCluster.Spec.Lans {
206+
lanSpec := &ctx.IONOSCloudCluster.Spec.Lans[i]
207+
ctx.Logger.Info(fmt.Sprintf("Reconciling %s Lan", lanSpec.Name))
208+
if lanSpec.LanID == nil {
209+
lanID, err := createLan(ctx, lanSpec.Public)
210+
if err != nil {
211+
return &reconcile.Result{}, err
212+
}
213+
lanSpec.LanID = lanID
220214
}
221-
ctx.IONOSCloudCluster.Spec.PrivateLanID = lanID
222-
}
223-
224-
ctx.IONOSCloudCluster.EnsureLan(v1alpha1.IONOSLanSpec{
225-
Name: "private",
226-
LanID: ctx.IONOSCloudCluster.Spec.PrivateLanID,
227-
Public: false,
228-
})
229215

230-
// check status
231-
lanId := fmt.Sprint(*ctx.IONOSCloudCluster.Spec.PrivateLanID)
232-
lan, resp, err := ctx.IONOSClient.GetLan(ctx, ctx.IONOSCloudCluster.Spec.DataCenterID, lanId)
216+
// check status
217+
lanId := fmt.Sprint(*lanSpec.LanID)
218+
lan, resp, err := ctx.IONOSClient.GetLan(ctx, ctx.IONOSCloudCluster.Spec.DataCenterID, lanId)
233219

234-
if err != nil && resp.StatusCode != http.StatusNotFound {
235-
return &reconcile.Result{}, errors.Wrap(err, "error getting private Lan")
236-
}
237-
238-
if resp.StatusCode == http.StatusNotFound || *lan.Metadata.State == STATE_BUSY {
239-
return &reconcile.Result{RequeueAfter: defaultRetryIntervalOnBusy}, errors.New("private Lan not available (yet)")
240-
}
241-
242-
conditions.MarkTrue(ctx.IONOSCloudCluster, v1alpha1.PrivateLanCreatedCondition)
243-
244-
return nil, nil
245-
}
246-
247-
func (r *IONOSCloudClusterReconciler) reconcilePublicLan(ctx *context.ClusterContext) (*reconcile.Result, error) {
248-
ctx.Logger.Info("Reconciling public Lan")
249-
if ctx.IONOSCloudCluster.Spec.PublicLanID == nil {
250-
lanID, err := createLan(ctx, true)
251-
if err != nil {
252-
return &reconcile.Result{}, err
220+
if err != nil && resp.StatusCode != http.StatusNotFound {
221+
return &reconcile.Result{}, errors.Wrap(err, fmt.Sprintf("error getting %s Lan", lanSpec.Name))
253222
}
254-
ctx.IONOSCloudCluster.Spec.PublicLanID = lanID
255-
}
256-
257-
ctx.IONOSCloudCluster.EnsureLan(v1alpha1.IONOSLanSpec{
258-
Name: "public",
259-
LanID: ctx.IONOSCloudCluster.Spec.PublicLanID,
260-
Public: true,
261-
})
262223

263-
// check status
264-
lanId := fmt.Sprint(*ctx.IONOSCloudCluster.Spec.PublicLanID)
265-
lan, resp, err := ctx.IONOSClient.GetLan(ctx, ctx.IONOSCloudCluster.Spec.DataCenterID, lanId)
266-
267-
if err != nil && resp.StatusCode != http.StatusNotFound {
268-
return &reconcile.Result{}, errors.Wrap(err, "error getting public Lan")
269-
}
270-
271-
if resp.StatusCode == http.StatusNotFound || *lan.Metadata.State == STATE_BUSY {
272-
return &reconcile.Result{RequeueAfter: defaultRetryIntervalOnBusy}, errors.New("public Lan not available (yet)")
224+
if resp.StatusCode == http.StatusNotFound || *lan.Metadata.State == STATE_BUSY {
225+
return &reconcile.Result{RequeueAfter: defaultRetryIntervalOnBusy}, errors.New(fmt.Sprintf("%s Lan not available (yet)", lanSpec.Name))
226+
}
273227
}
274228

275-
conditions.MarkTrue(ctx.IONOSCloudCluster, v1alpha1.PublicLanCreatedCondition)
229+
conditions.MarkTrue(ctx.IONOSCloudCluster, v1alpha1.LanCreatedCondition)
276230
return nil, nil
277231
}
278232

279-
func (r *IONOSCloudClusterReconciler) reconcileInternet(ctx *context.ClusterContext) (*reconcile.Result, error) {
280-
ctx.Logger.Info("Reconciling internet")
281-
if ctx.IONOSCloudCluster.Spec.InternetLanID == nil {
282-
lanID, err := createLan(ctx, true)
283-
if err != nil {
284-
return &reconcile.Result{}, err
285-
}
286-
ctx.IONOSCloudCluster.Spec.InternetLanID = lanID
287-
}
288-
289-
ctx.IONOSCloudCluster.EnsureLan(v1alpha1.IONOSLanSpec{
290-
Name: "internet",
291-
LanID: ctx.IONOSCloudCluster.Spec.InternetLanID,
292-
Public: true,
293-
})
294-
295-
// check status
296-
lanId := fmt.Sprint(*ctx.IONOSCloudCluster.Spec.InternetLanID)
297-
lan, resp, err := ctx.IONOSClient.GetLan(ctx, ctx.IONOSCloudCluster.Spec.DataCenterID, lanId)
233+
func (r *IONOSCloudClusterReconciler) reconcileLoadBalancer(ctx *context.ClusterContext) (*reconcile.Result, error) {
234+
ctx.Logger.Info("Reconciling LoadBalancer")
235+
lbSpec := &ctx.IONOSCloudCluster.Spec.LoadBalancer
236+
listenerLan := ctx.IONOSCloudCluster.Lan(lbSpec.ListenerLanRef.Name)
237+
targetLan := ctx.IONOSCloudCluster.Lan(lbSpec.TargetLanRef.Name)
298238

299-
if err != nil && resp.StatusCode != http.StatusNotFound {
300-
return &reconcile.Result{}, errors.New("error getting internet Lan")
239+
if listenerLan == nil {
240+
return &reconcile.Result{RequeueAfter: defaultRetryIntervalOnBusy}, errors.New(fmt.Sprintf("listener lb %s Lan not available (yet)", lbSpec.ListenerLanRef.Name))
301241
}
302-
303-
if resp.StatusCode == http.StatusNotFound || *lan.Metadata.State == STATE_BUSY {
304-
return &reconcile.Result{RequeueAfter: defaultRetryIntervalOnBusy}, errors.New("internet Lan not available (yet)")
242+
if targetLan == nil {
243+
return &reconcile.Result{RequeueAfter: defaultRetryIntervalOnBusy}, errors.New(fmt.Sprintf("target lb %s Lan not available (yet)", lbSpec.TargetLanRef.Name))
305244
}
306245

307-
conditions.MarkTrue(ctx.IONOSCloudCluster, v1alpha1.InternetLanCreatedCondition)
308-
309-
return nil, nil
310-
}
311-
312-
func (r *IONOSCloudClusterReconciler) reconcileLoadBalancer(ctx *context.ClusterContext) (*reconcile.Result, error) {
313-
ctx.Logger.Info("Reconciling LoadBalancer")
314-
if ctx.IONOSCloudCluster.Spec.LoadBalancerID == "" {
246+
if lbSpec.ID == "" {
315247
loadBalancerName := fmt.Sprintf("lb-%s", ctx.Cluster.Name)
316248
loadBalancer := ionoscloud.NetworkLoadBalancer{
317249
Entities: &ionoscloud.NetworkLoadBalancerEntities{
@@ -330,31 +262,21 @@ func (r *IONOSCloudClusterReconciler) reconcileLoadBalancer(ctx *context.Cluster
330262
},
331263
},
332264
Properties: &ionoscloud.NetworkLoadBalancerProperties{
333-
ListenerLan: ctx.IONOSCloudCluster.Spec.PublicLanID,
265+
ListenerLan: listenerLan.LanID,
334266
Name: &loadBalancerName,
335-
TargetLan: ctx.IONOSCloudCluster.Spec.PrivateLanID,
267+
TargetLan: targetLan.LanID,
336268
Ips: &[]string{ctx.IONOSCloudCluster.Spec.ControlPlaneEndpoint.Host},
337269
},
338270
}
339271
loadBalancer, _, err := ctx.IONOSClient.CreateLoadBalancer(ctx, ctx.IONOSCloudCluster.Spec.DataCenterID, loadBalancer)
340272
if err != nil {
341273
return &reconcile.Result{}, err
342274
}
343-
ctx.IONOSCloudCluster.Spec.LoadBalancerID = *loadBalancer.Id
344-
}
345-
346-
ctx.IONOSCloudCluster.Spec.LoadBalancer = &v1alpha1.IONOSLoadBalancerSpec{
347-
ID: ctx.IONOSCloudCluster.Spec.LoadBalancerID,
348-
ListenerLanRef: v1alpha1.IONOSLanRefSpec{
349-
Name: "public",
350-
},
351-
TargetLanRef: v1alpha1.IONOSLanRefSpec{
352-
Name: "private",
353-
},
275+
lbSpec.ID = *loadBalancer.Id
354276
}
355277

356278
// check status
357-
loadBalancer, resp, err := ctx.IONOSClient.GetLoadBalancer(ctx, ctx.IONOSCloudCluster.Spec.DataCenterID, ctx.IONOSCloudCluster.Spec.LoadBalancerID)
279+
loadBalancer, resp, err := ctx.IONOSClient.GetLoadBalancer(ctx, ctx.IONOSCloudCluster.Spec.DataCenterID, lbSpec.ID)
358280
if err != nil && resp.StatusCode != http.StatusNotFound {
359281
return &reconcile.Result{}, errors.Wrap(err, "error getting loadbalancer")
360282
}

0 commit comments

Comments
 (0)