Skip to content

Commit a9b168e

Browse files
edipascaleFrostman
authored andcommitted
chore: complete hydration checks for switches
same as the previous commit but in reverse direction. note that to avoid a dependecy cycle between wiringapi and gwapi here we use k8s unstructured lists Signed-off-by: Emanuele Di Pascale <emanuele@githedgehog.com>
1 parent f0c825b commit a9b168e

File tree

2 files changed

+81
-2
lines changed

2 files changed

+81
-2
lines changed

api/wiring/v1beta1/switch_types.go

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import (
2525
"go.githedgehog.com/fabric/api/meta"
2626
kapierrors "k8s.io/apimachinery/pkg/api/errors"
2727
kmetav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
29+
"k8s.io/apimachinery/pkg/runtime/schema"
2830
ktypes "k8s.io/apimachinery/pkg/types"
2931
kclient "sigs.k8s.io/controller-runtime/pkg/client"
3032
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
@@ -232,8 +234,6 @@ func (sw *Switch) HydrationValidation(ctx context.Context, kube kclient.Reader,
232234
if err := kube.List(ctx, switches); err != nil {
233235
return errors.Wrapf(err, "failed to list switches for hydration validation")
234236
}
235-
// TODO: collect gateways as well for VTEP and protocol IP uniqueness checks
236-
// (cannot be done now as gateway webhook would create a circular dependency)
237237

238238
leafASNs := map[uint32]bool{}
239239
VTEPs := map[string]bool{}
@@ -286,6 +286,31 @@ func (sw *Switch) HydrationValidation(ctx context.Context, kube kclient.Reader,
286286
}
287287
}
288288

289+
// collect gateways as well for VTEP and protocol IP uniqueness checks
290+
// use unstructured list to avoid import dependency cycle
291+
if fabricCfg != nil && fabricCfg.EnableGateway {
292+
gateways := &unstructured.UnstructuredList{}
293+
gateways.SetGroupVersionKind(schema.GroupVersionKind{
294+
Group: "gateway.githedgehog.com", Version: "v1alpha1", Kind: "GatewayList",
295+
})
296+
if err := kube.List(ctx, gateways); err != nil {
297+
return errors.Wrapf(err, "failed to list gateways for hydration validation")
298+
}
299+
300+
for _, gw := range gateways.Items {
301+
spec, ok := gw.Object["spec"].(map[string]interface{})
302+
if !ok {
303+
continue
304+
}
305+
if vtepIP, ok := spec["vtepIP"].(string); ok && vtepIP != "" {
306+
VTEPs[vtepIP] = true
307+
}
308+
if protoIP, ok := spec["protocolIP"].(string); ok && protoIP != "" {
309+
protocolIPs[protoIP] = true
310+
}
311+
}
312+
}
313+
289314
if sw.Spec.IP != "" {
290315
swIP, err := netip.ParsePrefix(sw.Spec.IP)
291316
if err != nil {

api/wiring/v1beta1/switch_types_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"testing"
88

99
"github.com/stretchr/testify/require"
10+
gwapi "go.githedgehog.com/fabric/api/gateway/v1alpha1"
1011
"go.githedgehog.com/fabric/api/meta"
1112
wiringapi "go.githedgehog.com/fabric/api/wiring/v1beta1"
1213
kmetav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -20,6 +21,7 @@ func TestHydrationValidation(t *testing.T) {
2021

2122
scheme := runtime.NewScheme()
2223
require.NoError(t, wiringapi.AddToScheme(scheme))
24+
require.NoError(t, gwapi.AddToScheme(scheme))
2325
leafSwitch := &wiringapi.Switch{
2426
ObjectMeta: kmetav1.ObjectMeta{
2527
Name: "leaf1",
@@ -91,6 +93,7 @@ func TestHydrationValidation(t *testing.T) {
9193
ManagementSubnet: "172.30.0.0/21",
9294
ManagementDHCPStart: "172.30.4.0",
9395
ManagementDHCPEnd: "172.30.7.254",
96+
EnableGateway: true,
9497
}
9598

9699
for _, test := range []struct {
@@ -307,6 +310,57 @@ func TestHydrationValidation(t *testing.T) {
307310
dut: mclagSwitch,
308311
expectError: true,
309312
},
313+
{
314+
name: "VTEPCollisionWithGateway",
315+
objects: []kclient.Object{
316+
&gwapi.Gateway{
317+
ObjectMeta: kmetav1.ObjectMeta{
318+
Name: "gw-1",
319+
Namespace: "default",
320+
},
321+
Spec: gwapi.GatewaySpec{
322+
ProtocolIP: "172.30.8.45/32",
323+
VTEPIP: "172.30.12.0/32",
324+
},
325+
},
326+
},
327+
dut: leafSwitch,
328+
expectError: true,
329+
},
330+
{
331+
name: "ProtocolIPCollisionWithGateway",
332+
objects: []kclient.Object{
333+
&gwapi.Gateway{
334+
ObjectMeta: kmetav1.ObjectMeta{
335+
Name: "gw-1",
336+
Namespace: "default",
337+
},
338+
Spec: gwapi.GatewaySpec{
339+
ProtocolIP: "172.30.8.2/32",
340+
VTEPIP: "172.30.12.45/32",
341+
},
342+
},
343+
},
344+
dut: leafSwitch,
345+
expectError: true,
346+
},
347+
{
348+
name: "noCollisionWithGateway",
349+
objects: []kclient.Object{
350+
&gwapi.Gateway{
351+
ObjectMeta: kmetav1.ObjectMeta{
352+
Name: "gw-1",
353+
Namespace: "default",
354+
},
355+
Spec: gwapi.GatewaySpec{
356+
ProtocolIP: "172.30.8.45/32",
357+
VTEPIP: "172.30.12.45/32",
358+
},
359+
},
360+
},
361+
dut: leafSwitch,
362+
expectError: false,
363+
},
310364
{
311365
name: "mclagPeerAllGood",
312366
objects: []kclient.Object{

0 commit comments

Comments
 (0)