Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions api/core/v1alpha1/interface_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,11 @@ type Interface struct {
Status InterfaceStatus `json:"status,omitempty,omitzero"`
}

// HasIPv4 reports whether the Interface is configured as a routed IPv4 interface.
func (in *Interface) HasIPv4() bool {
return in.Spec.Switchport == nil && in.Spec.IPv4 != nil
}

// GetConditions implements conditions.Getter.
func (in *Interface) GetConditions() []metav1.Condition {
return in.Status.Conditions
Expand Down
21 changes: 21 additions & 0 deletions api/evpn/v1alpha1/groupversion_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,24 @@ const (
// with the value set to the owning Fabric's name.
FabricLabel = "evpn.networking.metal.ironcore.dev/fabric"
)

// Fabric condition types.
const (
// UnderlayConvergedCondition reports whether all underlay IGP adjacencies are formed.
UnderlayConvergedCondition = "UnderlayConverged"

// OverlayConvergedCondition reports whether all overlay BGP sessions are established.
OverlayConvergedCondition = "OverlayConverged"
)

// Fabric condition reasons.
const (
// ConvergedReason indicates all child resources report Operational=True.
ConvergedReason = "Converged"

// NotConvergedReason indicates one or more child resources are not yet operational.
NotConvergedReason = "NotConverged"

// NoResourcesReason indicates no child resources exist yet for this condition.
NoResourcesReason = "NoResources"
)
1 change: 1 addition & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,7 @@ func main() { //nolint:gocyclo
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("fabric-controller"),
Provider: prov,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "Failed to create controller", "controller", "Fabric")
os.Exit(1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ kind: Interface
metadata:
labels:
networking.metal.ironcore.dev/role: fabric
networking.metal.ironcore.dev/interface-neighbor: spine1-eth1-1
name: leaf1-eth1-1
spec:
deviceRef:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ kind: Interface
metadata:
labels:
networking.metal.ironcore.dev/role: fabric
networking.metal.ironcore.dev/interface-neighbor: spine2-eth1-1
name: leaf1-eth1-2
spec:
deviceRef:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ kind: Interface
metadata:
labels:
networking.metal.ironcore.dev/role: fabric
networking.metal.ironcore.dev/interface-neighbor: spine1-eth1-2
name: leaf2-eth1-1
spec:
deviceRef:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ kind: Interface
metadata:
labels:
networking.metal.ironcore.dev/role: fabric
networking.metal.ironcore.dev/interface-neighbor: spine2-eth1-2
name: leaf2-eth1-2
spec:
deviceRef:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ kind: Interface
metadata:
labels:
networking.metal.ironcore.dev/role: fabric
networking.metal.ironcore.dev/interface-neighbor: spine1-eth1-3
name: leaf3-eth1-1
spec:
deviceRef:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ kind: Interface
metadata:
labels:
networking.metal.ironcore.dev/role: fabric
networking.metal.ironcore.dev/interface-neighbor: spine2-eth1-3
name: leaf3-eth1-2
spec:
deviceRef:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ kind: Interface
metadata:
labels:
networking.metal.ironcore.dev/role: fabric
networking.metal.ironcore.dev/interface-neighbor: leaf1-eth1-1
name: spine1-eth1-1
spec:
deviceRef:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ kind: Interface
metadata:
labels:
networking.metal.ironcore.dev/role: fabric
networking.metal.ironcore.dev/interface-neighbor: leaf2-eth1-1
name: spine1-eth1-2
spec:
deviceRef:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ kind: Interface
metadata:
labels:
networking.metal.ironcore.dev/role: fabric
networking.metal.ironcore.dev/interface-neighbor: leaf3-eth1-1
name: spine1-eth1-3
spec:
deviceRef:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ kind: Interface
metadata:
labels:
networking.metal.ironcore.dev/role: fabric
networking.metal.ironcore.dev/interface-neighbor: leaf1-eth1-2
name: spine2-eth1-1
spec:
deviceRef:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ kind: Interface
metadata:
labels:
networking.metal.ironcore.dev/role: fabric
networking.metal.ironcore.dev/interface-neighbor: leaf2-eth1-2
name: spine2-eth1-2
spec:
deviceRef:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ kind: Interface
metadata:
labels:
networking.metal.ironcore.dev/role: fabric
networking.metal.ironcore.dev/interface-neighbor: leaf3-eth1-2
name: spine2-eth1-3
spec:
deviceRef:
Expand Down
24 changes: 23 additions & 1 deletion internal/controller/core/ospf_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,9 @@ func (r *OSPFReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager)
newInterface := e.ObjectNew.(*v1alpha1.Interface)
oldConfigured := conditions.Get(oldInterface, v1alpha1.ConfiguredCondition)
newConfigured := conditions.Get(newInterface, v1alpha1.ConfiguredCondition)
return ((oldConfigured == nil) != (newConfigured == nil)) || (newConfigured != nil && oldConfigured.Status != newConfigured.Status)
return oldInterface.HasIPv4() != newInterface.HasIPv4() ||
((oldConfigured == nil) != (newConfigured == nil)) ||
(newConfigured != nil && oldConfigured.Status != newConfigured.Status)
},
GenericFunc: func(e event.GenericEvent) bool {
return false
Expand Down Expand Up @@ -327,6 +329,26 @@ func (r *OSPFReconciler) reconcile(ctx context.Context, s *ospfScope) (reterr er
return err
}

if intf.Spec.DeviceRef.Name != s.Device.Name {
conditions.Set(s.OSPF, metav1.Condition{
Type: v1alpha1.ConfiguredCondition,
Status: metav1.ConditionFalse,
Reason: v1alpha1.CrossDeviceReferenceReason,
Message: fmt.Sprintf("interface %q belongs to device %q, not %q", ref.Name, intf.Spec.DeviceRef.Name, s.Device.Name),
})
return reconcile.TerminalError(fmt.Errorf("interface %q belongs to a different device", ref.Name))
}

if !intf.HasIPv4() {
conditions.Set(s.OSPF, metav1.Condition{
Type: v1alpha1.ConfiguredCondition,
Status: metav1.ConditionFalse,
Reason: v1alpha1.IPAddressingNotFoundReason,
Message: fmt.Sprintf("interface %q has no IPv4 configuration", ref.Name),
})
return reconcile.TerminalError(fmt.Errorf("interface %q has no IPv4 configuration", ref.Name))
}

if !conditions.IsConfigured(intf) {
conditions.Set(s.OSPF, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Expand Down
65 changes: 65 additions & 0 deletions internal/controller/core/ospf_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"

"github.com/ironcore-dev/network-operator/api/core/v1alpha1"
"github.com/ironcore-dev/network-operator/internal/conditions"
)

var _ = Describe("OSPF Controller", func() {
Expand Down Expand Up @@ -118,6 +119,70 @@ var _ = Describe("OSPF Controller", func() {
})
})

Context("When a referenced interface has no IPv4 configuration", func() {
var (
name string
key client.ObjectKey
)

BeforeEach(func() {
device := &v1alpha1.Device{
ObjectMeta: metav1.ObjectMeta{GenerateName: "test-ospf-l2-intf-", Namespace: metav1.NamespaceDefault},
Spec: v1alpha1.DeviceSpec{Endpoint: v1alpha1.Endpoint{Address: "192.168.10.4:9339"}},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
name = device.Name
key = client.ObjectKey{Name: name, Namespace: metav1.NamespaceDefault}

intf := &v1alpha1.Interface{
ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: metav1.NamespaceDefault},
Spec: v1alpha1.InterfaceSpec{
DeviceRef: v1alpha1.LocalObjectReference{Name: name},
Name: "eth1",
AdminState: v1alpha1.AdminStateUp,
Type: v1alpha1.InterfaceTypePhysical,
},
}
Expect(k8sClient.Create(ctx, intf)).To(Succeed())
Eventually(func(g Gomega) {
current := &v1alpha1.Interface{}
g.Expect(k8sClient.Get(ctx, key, current)).To(Succeed())
g.Expect(conditions.IsConfigured(current)).To(BeTrue())
}).Should(Succeed())

ospf := &v1alpha1.OSPF{
ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: metav1.NamespaceDefault},
Spec: v1alpha1.OSPFSpec{
DeviceRef: v1alpha1.LocalObjectReference{Name: name},
Instance: "UNDERLAY",
RouterID: "10.0.0.10",
InterfaceRefs: []v1alpha1.OSPFInterface{{
LocalObjectReference: v1alpha1.LocalObjectReference{Name: name},
Area: "0.0.0.0",
}},
},
}
Expect(k8sClient.Create(ctx, ospf)).To(Succeed())
})

AfterEach(func() {
Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, &v1alpha1.OSPF{ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: metav1.NamespaceDefault}}))).To(Succeed())
Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, &v1alpha1.Interface{ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: metav1.NamespaceDefault}}))).To(Succeed())
Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, &v1alpha1.Device{ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: metav1.NamespaceDefault}}))).To(Succeed())
})

It("Should set ConfiguredCondition to false", func() {
Eventually(func(g Gomega) {
resource := &v1alpha1.OSPF{}
g.Expect(k8sClient.Get(ctx, key, resource)).To(Succeed())
configured := meta.FindStatusCondition(resource.Status.Conditions, v1alpha1.ConfiguredCondition)
g.Expect(configured).NotTo(BeNil())
g.Expect(configured.Status).To(Equal(metav1.ConditionFalse))
g.Expect(configured.Reason).To(Equal(v1alpha1.IPAddressingNotFoundReason))
}).Should(Succeed())
})
})

Context("When an interfaceRef does not exist", func() {
var (
name string
Expand Down
Loading
Loading