Skip to content

Commit 4fa520d

Browse files
committed
feat: optional node network
1 parent 3ae36f4 commit 4fa520d

16 files changed

+131
-39
lines changed

api/v1alpha1/metalstackcluster_types.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ const (
3737
ClusterControlPlaneEndpointDefaultPort = 443
3838

3939
ClusterPaused clusterv1.ConditionType = clusterv1.PausedV1Beta2Condition
40+
ClusterNodeNetworkEnsured clusterv1.ConditionType = "ClusterNodeNetworkEnsured"
4041
ClusterControlPlaneIPEnsured clusterv1.ConditionType = "ClusterControlPlaneIPEnsured"
4142
)
4243

@@ -57,7 +58,9 @@ type MetalStackClusterSpec struct {
5758
ProjectID string `json:"projectID"`
5859

5960
// NodeNetworkID is the network ID in metal-stack in which the worker nodes and the firewall of the cluster are placed.
60-
NodeNetworkID string `json:"nodeNetworkID"`
61+
// If not provided this will automatically be acquired during reconcile.
62+
// +optional
63+
NodeNetworkID *string `json:"nodeNetworkID,omitempty"`
6164

6265
// ControlPlaneIP is the ip address in metal-stack on which the control plane will be exposed.
6366
// If this ip and the control plane endpoint are not provided, an ephemeral ip will automatically be acquired during reconcile.
@@ -153,6 +156,6 @@ func (c *MetalStackCluster) SetConditions(conditions clusterv1.Conditions) {
153156
c.Status.Conditions = conditions
154157
}
155158

156-
func (c *MetalStackCluster) GetClusterID() string {
159+
func (c *MetalStackCluster) GetClusterName() string {
157160
return fmt.Sprintf("%s.%s", c.GetNamespace(), c.GetName())
158161
}

api/v1alpha1/metalstackcluster_types_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ var _ = Describe("MetalStackCluster", func() {
1717
},
1818
}
1919

20-
clusterID := cluster.GetClusterID()
20+
clusterID := cluster.GetClusterName()
2121
Expect(utilvalidation.IsValidLabelValue(clusterID)).To(BeEmpty())
2222
})
2323

@@ -29,7 +29,7 @@ var _ = Describe("MetalStackCluster", func() {
2929
},
3030
}
3131

32-
clusterID := cluster.GetClusterID()
32+
clusterID := cluster.GetClusterName()
3333
Expect(clusterID).To(Equal("some-namespace.my-cluster"))
3434
})
3535
})

api/v1alpha1/zz_generated.deepcopy.go

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

config/clusterctl-templates/cluster-template-calico-lab.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ metadata:
3131
spec:
3232
projectID: ${METAL_PROJECT_ID}
3333
partition: ${METAL_PARTITION}
34-
nodeNetworkID: ${METAL_NODE_NETWORK_ID}
34+
nodeNetworkID: ${METAL_NODE_NETWORK_ID:=null}
3535
controlPlaneIP: ${CONTROL_PLANE_IP}
3636
firewallDeploymentRef:
3737
name: ${CLUSTER_NAME}

config/clusterctl-templates/cluster-template-calico.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ metadata:
3131
spec:
3232
projectID: ${METAL_PROJECT_ID}
3333
partition: ${METAL_PARTITION}
34-
nodeNetworkID: ${METAL_NODE_NETWORK_ID}
34+
nodeNetworkID: ${METAL_NODE_NETWORK_ID:=null}
3535
controlPlaneIP: ${CONTROL_PLANE_IP}
3636
firewallDeploymentRef:
3737
name: ${CLUSTER_NAME}

config/clusterctl-templates/cluster-template-pre-v1.33.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ metadata:
2727
spec:
2828
projectID: ${METAL_PROJECT_ID}
2929
partition: ${METAL_PARTITION}
30-
nodeNetworkID: ${METAL_NODE_NETWORK_ID}
30+
nodeNetworkID: ${METAL_NODE_NETWORK_ID:=null}
3131
controlPlaneIP: ${CONTROL_PLANE_IP}
3232
firewallDeploymentRef:
3333
name: ${CLUSTER_NAME}

config/clusterctl-templates/cluster-template.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ metadata:
2727
spec:
2828
projectID: ${METAL_PROJECT_ID}
2929
partition: ${METAL_PARTITION}
30-
nodeNetworkID: ${METAL_NODE_NETWORK_ID}
30+
nodeNetworkID: ${METAL_NODE_NETWORK_ID:=null}
3131
controlPlaneIP: ${CONTROL_PLANE_IP}
3232
firewallDeploymentRef:
3333
name: ${CLUSTER_NAME}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,9 @@ spec:
104104
- name
105105
type: object
106106
nodeNetworkID:
107-
description: NodeNetworkID is the network ID in metal-stack in which
108-
the worker nodes and the firewall of the cluster are placed.
107+
description: |-
108+
NodeNetworkID is the network ID in metal-stack in which the worker nodes and the firewall of the cluster are placed.
109+
If not provided this will automatically be acquired during reconcile.
109110
type: string
110111
partition:
111112
description: Partition is the data center partition in which the resources
@@ -116,7 +117,6 @@ spec:
116117
in which the associated metal-stack resources are created.
117118
type: string
118119
required:
119-
- nodeNetworkID
120120
- partition
121121
- projectID
122122
type: object

internal/controller/metalstackcluster_controller.go

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,16 @@ func (r *MetalStackClusterReconciler) metalStackFirewallToMetalStackCluster(log
303303
}
304304

305305
func (r *clusterReconciler) reconcile() error {
306+
nodeNetworkID, err := r.ensureNodeNetwork()
307+
if err != nil {
308+
conditions.MarkFalse(r.infraCluster, v1alpha1.ClusterNodeNetworkEnsured, "InternalError", clusterv1.ConditionSeverityError, "%s", err.Error())
309+
return fmt.Errorf("unable to ensure node network: %w", err)
310+
}
311+
conditions.MarkTrue(r.infraCluster, v1alpha1.ClusterNodeNetworkEnsured)
312+
r.infraCluster.Spec.NodeNetworkID = &nodeNetworkID
313+
314+
r.log.Info("reconciled node network", "network-id", nodeNetworkID)
315+
306316
if r.infraCluster.Spec.FirewallDeploymentRef != nil {
307317
err := r.ensureFirewallDeployment()
308318
if err != nil {
@@ -360,12 +370,53 @@ func (r *clusterReconciler) delete() error {
360370
}
361371
r.infraCluster.Spec.ControlPlaneIP = nil
362372

373+
err = r.deleteNodeNetwork()
374+
if err != nil {
375+
return fmt.Errorf("unable to delete node network: %w", err)
376+
}
377+
r.infraCluster.Spec.NodeNetworkID = nil
378+
363379
r.log.Info("deletion finished, removing finalizer")
364380
controllerutil.RemoveFinalizer(r.infraCluster, v1alpha1.ClusterFinalizer)
365381

366382
return err
367383
}
368384

385+
func (r *clusterReconciler) ensureNodeNetwork() (string, error) {
386+
if r.infraCluster.Spec.NodeNetworkID != nil {
387+
return *r.infraCluster.Spec.NodeNetworkID, nil
388+
}
389+
390+
resp, err := r.metalClient.Network().AllocateNetwork(network.NewAllocateNetworkParams().WithBody(&models.V1NetworkAllocateRequest{
391+
Projectid: r.infraCluster.Spec.ProjectID,
392+
Partitionid: r.infraCluster.Spec.Partition,
393+
Name: r.infraCluster.GetName(),
394+
Description: fmt.Sprintf("%s/%s", r.infraCluster.GetNamespace(), r.infraCluster.GetName()),
395+
Labels: map[string]string{
396+
v1alpha1.TagInfraClusterResource: r.infraCluster.GetClusterName(),
397+
},
398+
}).WithContext(r.ctx), nil)
399+
if err != nil {
400+
return "", fmt.Errorf("error creating node network: %w", err)
401+
}
402+
403+
return *resp.Payload.ID, nil
404+
}
405+
406+
func (r *clusterReconciler) deleteNodeNetwork() error {
407+
if r.infraCluster.Spec.NodeNetworkID == nil {
408+
return nil
409+
}
410+
411+
_, err := r.metalClient.Network().FreeNetwork(network.NewFreeNetworkParams().WithID(*r.infraCluster.Spec.NodeNetworkID).WithContext(r.ctx), nil)
412+
if err != nil {
413+
return err
414+
}
415+
r.log.Info("deleted node network")
416+
417+
return nil
418+
}
419+
369420
func (r *clusterReconciler) ensureFirewallDeployment() error {
370421
fwdeploy := &v1alpha1.MetalStackFirewallDeployment{}
371422
err := r.client.Get(r.ctx, types.NamespacedName{
@@ -415,12 +466,12 @@ func (r *clusterReconciler) ensureControlPlaneIP() (string, error) {
415466

416467
defaultNetwork := nwResp.Payload[0]
417468
resp, err := r.metalClient.IP().AllocateIP(ipmodels.NewAllocateIPParams().WithBody(&models.V1IPAllocateRequest{
418-
Description: fmt.Sprintf("%s control plane ip", r.infraCluster.GetClusterID()),
469+
Description: fmt.Sprintf("%s control plane ip", r.infraCluster.GetClusterName()),
419470
Name: r.infraCluster.GetName() + "-control-plane",
420471
Networkid: defaultNetwork.ID,
421472
Projectid: &r.infraCluster.Spec.ProjectID,
422473
Tags: []string{
423-
tag.New(tag.ClusterID, r.infraCluster.GetClusterID()),
474+
tag.New(tag.ClusterID, r.infraCluster.GetClusterName()),
424475
v1alpha1.TagControlPlanePurpose,
425476
},
426477
Type: ptr.To(models.V1IPBaseTypeEphemeral),

internal/controller/metalstackcluster_controller_test.go

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ var _ = Describe("MetalStackCluster Controller", func() {
107107
resource.Spec = v1alpha1.MetalStackClusterSpec{
108108
ControlPlaneEndpoint: v1alpha1.APIEndpoint{},
109109
ProjectID: "test-project",
110-
NodeNetworkID: "node-network-id",
110+
NodeNetworkID: nil,
111111
ControlPlaneIP: nil,
112112
Partition: "test-partition",
113113
}
@@ -229,7 +229,7 @@ var _ = Describe("MetalStackCluster Controller", func() {
229229
resource.Spec = v1alpha1.MetalStackClusterSpec{
230230
ControlPlaneEndpoint: v1alpha1.APIEndpoint{},
231231
ProjectID: "test-project",
232-
NodeNetworkID: "node-network-id",
232+
NodeNetworkID: nil,
233233
ControlPlaneIP: nil,
234234
Partition: "test-partition",
235235
}
@@ -271,11 +271,11 @@ var _ = Describe("MetalStackCluster Controller", func() {
271271
IP: func(m *mock.Mock) {
272272
m.On("AllocateIP", testcommon.MatchIgnoreContext(testingT, metalip.NewAllocateIPParams().WithBody(&models.V1IPAllocateRequest{
273273
Tags: []string{
274-
"cluster.metal-stack.io/id=" + resource.GetClusterID(),
274+
"cluster.metal-stack.io/id=" + resource.GetClusterName(),
275275
"metal-stack.infrastructure.cluster.x-k8s.io/purpose=control-plane",
276276
},
277277
Name: resource.Name + "-control-plane",
278-
Description: resource.GetClusterID() + " control plane ip",
278+
Description: resource.GetClusterName() + " control plane ip",
279279
Networkid: ptr.To("internet"),
280280
Projectid: ptr.To("test-project"),
281281
Type: ptr.To("ephemeral"),
@@ -286,6 +286,26 @@ var _ = Describe("MetalStackCluster Controller", func() {
286286
}, nil)
287287
},
288288
Network: func(m *mock.Mock) {
289+
m.On("AllocateNetwork", testcommon.MatchIgnoreContext(testingT, metalnetwork.NewAllocateNetworkParams().WithBody(&models.V1NetworkAllocateRequest{
290+
Name: resource.Name,
291+
Description: resource.Namespace + "/" + resource.Name,
292+
Labels: map[string]string{
293+
"cluster.metal-stack.io/id": string(resource.UID),
294+
},
295+
Partitionid: "test-partition",
296+
Projectid: "test-project",
297+
})), nil).Return(&metalnetwork.AllocateNetworkCreated{
298+
Payload: &models.V1NetworkResponse{
299+
Labels: map[string]string{
300+
"cluster.metal-stack.io/id": string(resource.UID),
301+
},
302+
Partitionid: "test-partition",
303+
Projectid: "test-project",
304+
ID: ptr.To("test-network"),
305+
Prefixes: []string{"192.168.42.0/24"},
306+
},
307+
}, nil)
308+
289309
m.On("FindNetworks", testcommon.MatchIgnoreContext(testingT, metalnetwork.NewFindNetworksParams().WithBody(&models.V1NetworkFindRequest{
290310
Labels: map[string]string{
291311
"network.metal-stack.io/default": "",
@@ -325,6 +345,10 @@ var _ = Describe("MetalStackCluster Controller", func() {
325345

326346
Expect(k8sClient.Get(ctx, typeNamespacedName, resource)).To(Succeed())
327347

348+
Expect(resource.Status.Conditions).To(ContainElement(MatchFields(IgnoreExtras, Fields{
349+
"Type": Equal(v1alpha1.ClusterNodeNetworkEnsured),
350+
"Status": Equal(corev1.ConditionTrue),
351+
})))
328352
Expect(resource.Status.Conditions).To(ContainElement(MatchFields(IgnoreExtras, Fields{
329353
"Type": Equal(v1alpha1.ClusterControlPlaneIPEnsured),
330354
"Status": Equal(corev1.ConditionTrue),
@@ -351,7 +375,7 @@ var _ = Describe("MetalStackCluster Controller", func() {
351375
resource.Spec = v1alpha1.MetalStackClusterSpec{
352376
ControlPlaneEndpoint: v1alpha1.APIEndpoint{},
353377
ProjectID: "test-project",
354-
NodeNetworkID: nodeNetworkID,
378+
NodeNetworkID: &nodeNetworkID,
355379
ControlPlaneIP: &controlPlaneIP,
356380
Partition: "test-partition",
357381
}
@@ -402,6 +426,10 @@ var _ = Describe("MetalStackCluster Controller", func() {
402426

403427
return resource.Status.Conditions
404428
}, "20s").Should(ContainElements(
429+
MatchFields(IgnoreExtras, Fields{
430+
"Type": Equal(v1alpha1.ClusterNodeNetworkEnsured),
431+
"Status": Equal(corev1.ConditionTrue),
432+
}),
405433
MatchFields(IgnoreExtras, Fields{
406434
"Type": Equal(v1alpha1.ClusterControlPlaneIPEnsured),
407435
"Status": Equal(corev1.ConditionTrue),
@@ -447,6 +475,10 @@ var _ = Describe("MetalStackCluster Controller", func() {
447475

448476
return resource.Status.Conditions
449477
}, "20s").Should(ContainElements(
478+
MatchFields(IgnoreExtras, Fields{
479+
"Type": Equal(v1alpha1.ClusterNodeNetworkEnsured),
480+
"Status": Equal(corev1.ConditionTrue),
481+
}),
450482
MatchFields(IgnoreExtras, Fields{
451483
"Type": Equal(v1alpha1.ClusterControlPlaneIPEnsured),
452484
"Status": Equal(corev1.ConditionTrue),

0 commit comments

Comments
 (0)