@@ -29,6 +29,7 @@ import (
2929 "sigs.k8s.io/controller-runtime/pkg/predicate"
3030 "sigs.k8s.io/controller-runtime/pkg/reconcile"
3131
32+ nxv1alpha1 "github.com/ironcore-dev/network-operator/api/cisco/nx/v1alpha1"
3233 "github.com/ironcore-dev/network-operator/api/core/v1alpha1"
3334 "github.com/ironcore-dev/network-operator/internal/conditions"
3435 "github.com/ironcore-dev/network-operator/internal/deviceutil"
@@ -204,6 +205,9 @@ type lldpScope struct {
204205 Connection * deviceutil.Connection
205206 ProviderConfig * provider.ProviderConfig
206207 Provider provider.LLDPProvider
208+ // Interfaces maps k8s object names to Interface objects associated with the LLDP, required by
209+ // - cisco/nx
210+ Interfaces map [string ]* v1alpha1.Interface
207211}
208212
209213func (r * LLDPReconciler ) reconcile (ctx context.Context , s * lldpScope ) (_ ctrl.Result , reterr error ) {
@@ -244,6 +248,7 @@ func (r *LLDPReconciler) reconcile(ctx context.Context, s *lldpScope) (_ ctrl.Re
244248 err := s .Provider .EnsureLLDP (ctx , & provider.LLDPRequest {
245249 LLDP : s .LLDP ,
246250 ProviderConfig : s .ProviderConfig ,
251+ Interfaces : s .Interfaces ,
247252 })
248253
249254 cond := conditions .FromError (err )
@@ -278,7 +283,7 @@ func (r *LLDPReconciler) reconcile(ctx context.Context, s *lldpScope) (_ ctrl.Re
278283}
279284
280285// validateProviderConfigRef checks if the referenced provider configuration is compatible with the target platform.
281- func (r * LLDPReconciler ) validateProviderConfigRef (_ context.Context , s * lldpScope ) error {
286+ func (r * LLDPReconciler ) validateProviderConfigRef (ctx context.Context , s * lldpScope ) error {
282287 if s .LLDP .Spec .ProviderConfigRef == nil {
283288 return nil
284289 }
@@ -302,9 +307,26 @@ func (r *LLDPReconciler) validateProviderConfigRef(_ context.Context, s *lldpSco
302307 Type : v1alpha1 .ConfiguredCondition ,
303308 Status : metav1 .ConditionFalse ,
304309 Reason : v1alpha1 .IncompatibleProviderConfigRef ,
305- Message : fmt .Sprintf ("ProviderConfigRef is not compatible with Device: %v " , err ),
310+ Message : fmt .Sprintf ("ProviderConfigRef kind '%s' with API version '%s' is not compatible with this device type " , s . LLDP . Spec . ProviderConfigRef . Kind , s . LLDP . Spec . ProviderConfigRef . APIVersion ),
306311 })
307- return reconcile .TerminalError (fmt .Errorf ("unsupported provider config ref kind %q on this provider" , gv ))
312+ return reconcile .TerminalError (fmt .Errorf ("unsupported pProviderConfigRef Kind %q on this provider" , gv ))
313+ }
314+
315+ gvk := schema.GroupVersionKind {
316+ Group : gv .Group ,
317+ Version : gv .Version ,
318+ Kind : s .LLDP .Spec .ProviderConfigRef .Kind ,
319+ }
320+
321+ // only cisco/nx for the moment
322+ if gvk == nxv1alpha1 .GroupVersion .WithKind ("LLDPConfig" ) {
323+ lc := new (nxv1alpha1.LLDPConfig )
324+ if err := s .ProviderConfig .Into (lc ); err != nil {
325+ return reconcile .TerminalError (fmt .Errorf ("failed to parse provider config into LLDPConfig: %w" , err ))
326+ }
327+ if err := r .validateProviderConfigNXOS (ctx , lc , s ); err != nil {
328+ return reconcile .TerminalError (fmt .Errorf ("configuration error in provider config ref %w" , err ))
329+ }
308330 }
309331 return nil
310332}
@@ -325,8 +347,50 @@ func (r *LLDPReconciler) validateUniqueLLDPPerDevice(ctx context.Context, s *lld
325347 Reason : v1alpha1 .DuplicateResourceOnDevice ,
326348 Message : fmt .Sprintf ("Another LLDP (%s) already exists for device %s" , lldp .Name , s .LLDP .Spec .DeviceRef .Name ),
327349 })
328- return reconcile .TerminalError (fmt .Errorf ("only one lldp resource allowed per device (%s)" , s .LLDP .Spec .DeviceRef .Name ))
350+ return reconcile .TerminalError (fmt .Errorf ("only one LLDP resource allowed per device (%s)" , s .LLDP .Spec .DeviceRef .Name ))
351+ }
352+ }
353+ return nil
354+ }
355+
356+ // validateProviderConfigNXOS validates the provider configuration for the NXOS platform.
357+ // Updates scope and adds interfaces referenced by the LLDP configuration to the scope.
358+ func (r * LLDPReconciler ) validateProviderConfigNXOS (ctx context.Context , cfg * nxv1alpha1.LLDPConfig , s * lldpScope ) error {
359+ // Ensure all referenced interfaces exist and belong to she same device as the LLDP.
360+ s .Interfaces = make (map [string ]* v1alpha1.Interface )
361+ for _ , ifCfg := range cfg .Spec .InterfaceConfigurations {
362+ intf := new (v1alpha1.Interface )
363+ if err := r .Get (ctx , client.ObjectKey {Name : ifCfg .InterfaceRef .Name , Namespace : s .LLDP .Namespace }, intf ); err != nil {
364+ if apierrors .IsNotFound (err ) {
365+ conditions .Set (s .LLDP , metav1.Condition {
366+ Type : v1alpha1 .ConfiguredCondition ,
367+ Status : metav1 .ConditionFalse ,
368+ Reason : v1alpha1 .InterfaceNotFoundReason ,
369+ Message : fmt .Sprintf ("Referenced interface %q not found" , ifCfg .InterfaceRef .Name ),
370+ })
371+ return fmt .Errorf ("referenced interface %q not found: %w" , ifCfg .InterfaceRef .Name , err )
372+ }
373+ return fmt .Errorf ("failed to get referenced interface %q: %w" , ifCfg .InterfaceRef .Name , err )
374+ }
375+ if intf .Spec .DeviceRef .Name != s .Device .Name {
376+ conditions .Set (s .LLDP , metav1.Condition {
377+ Type : v1alpha1 .ConfiguredCondition ,
378+ Status : metav1 .ConditionFalse ,
379+ Reason : v1alpha1 .CrossDeviceReferenceReason ,
380+ Message : fmt .Sprintf ("Referenced interface %q belongs to device %q, expected %q" , ifCfg .InterfaceRef .Name , intf .Spec .DeviceRef .Name , s .Device .Name ),
381+ })
382+ return fmt .Errorf ("referenced interface %q belongs to device %q, expected %q" , ifCfg .InterfaceRef .Name , intf .Spec .DeviceRef .Name , s .Device .Name )
383+ }
384+ if intf .Spec .Type != v1alpha1 .InterfaceTypePhysical && intf .Spec .Type != v1alpha1 .InterfaceTypeAggregate {
385+ conditions .Set (s .LLDP , metav1.Condition {
386+ Type : v1alpha1 .ConfiguredCondition ,
387+ Status : metav1 .ConditionFalse ,
388+ Reason : v1alpha1 .InvalidInterfaceTypeReason ,
389+ Message : fmt .Sprintf ("Referenced interface %q is of type %q, expected %q or %q" , ifCfg .InterfaceRef .Name , intf .Spec .Type , v1alpha1 .InterfaceTypePhysical , v1alpha1 .InterfaceTypeAggregate ),
390+ })
391+ return fmt .Errorf ("referenced interface %q is of type %q, expected %q or %q" , ifCfg .InterfaceRef .Name , intf .Spec .Type , v1alpha1 .InterfaceTypePhysical , v1alpha1 .InterfaceTypeAggregate )
329392 }
393+ s .Interfaces [ifCfg .InterfaceRef .Name ] = intf
330394 }
331395 return nil
332396}
@@ -376,7 +440,7 @@ func (r *LLDPReconciler) mapProviderConfigToLLDP(ctx context.Context, obj client
376440
377441 list := & v1alpha1.LLDPList {}
378442 if err := r .List (ctx , list , client .InNamespace (obj .GetNamespace ())); err != nil {
379- log .Error (err , "Failed to list LLDPs" )
443+ log .Error (err , "failed to list LLDPs" )
380444 return nil
381445 }
382446
@@ -388,7 +452,7 @@ func (r *LLDPReconciler) mapProviderConfigToLLDP(ctx context.Context, obj client
388452 m .Spec .ProviderConfigRef .Name == obj .GetName () &&
389453 m .Spec .ProviderConfigRef .Kind == gkv .Kind &&
390454 m .Spec .ProviderConfigRef .APIVersion == gkv .GroupVersion ().Identifier () {
391- log .Info ("Enqueuing LLDP for reconciliation" , "LLDP" , klog .KObj (& m ))
455+ log .Info ("Found matching LLDP for provider config change, enqueuing for reconciliation" , "LLDP" , klog .KObj (& m ))
392456 requests = append (requests , reconcile.Request {
393457 NamespacedName : types.NamespacedName {
394458 Name : m .Name ,
0 commit comments