From 2f56f2cc77c87f1ea02ff76c74824807a1872636 Mon Sep 17 00:00:00 2001 From: Kajol Asabe <114986456+kasabe28@users.noreply.github.com> Date: Fri, 5 Apr 2024 13:21:12 +0530 Subject: [PATCH] Implement `Network` peering controller and extend `NetworkPeeringStatus` with `State` field (#1026) * Extend NetworkPeeringStatus with State field * Implement network peering controller and add tests * change network peering status state name from Initial to Pending * modify network protection controller to keep finalizer if it has valid peering * fix claimer key creation in network release controller --- api/networking/v1alpha1/network_type.go | 12 + .../applyconfigurations/internal/internal.go | 3 + .../v1alpha1/networkpeeringstatus.go | 15 +- client-go/openapi/zz_generated.openapi.go | 7 + cmd/ironcore-controller-manager/main.go | 17 + internal/apis/networking/network_type.go | 12 + .../v1alpha1/zz_generated.conversion.go | 2 + internal/client/networking/network.go | 28 + .../networking/network_peering_controller.go | 224 +++++++ .../network_peering_controller_test.go | 553 ++++++++++++++++++ .../network_protection_controller.go | 44 +- .../network_protection_controller_test.go | 101 ++++ .../networking/network_release_controller.go | 5 +- internal/controllers/networking/suite_test.go | 6 + 14 files changed, 1024 insertions(+), 5 deletions(-) create mode 100644 internal/client/networking/network.go create mode 100644 internal/controllers/networking/network_peering_controller.go create mode 100644 internal/controllers/networking/network_peering_controller_test.go diff --git a/api/networking/v1alpha1/network_type.go b/api/networking/v1alpha1/network_type.go index 2cd81f8f3..f47e1f4a7 100644 --- a/api/networking/v1alpha1/network_type.go +++ b/api/networking/v1alpha1/network_type.go @@ -68,10 +68,22 @@ type NetworkStatus struct { // +enum type NetworkState string +// NetworkPeeringState is the state a NetworkPeering can be in +type NetworkPeeringState string + +const ( + // NetworkPeeringStatePending signals that the network peering is not applied. + NetworkPeeringStatePending NetworkPeeringState = "Pending" + // NetworkPeeringStateApplied signals that the network peering is applied. + NetworkPeeringStateApplied NetworkPeeringState = "Applied" +) + // NetworkPeeringStatus is the status of a network peering. type NetworkPeeringStatus struct { // Name is the name of the network peering. Name string `json:"name"` + // State represents the network peering state + State NetworkPeeringState `json:"state,omitempty"` } const ( diff --git a/client-go/applyconfigurations/internal/internal.go b/client-go/applyconfigurations/internal/internal.go index 10807291d..edc14f8e5 100644 --- a/client-go/applyconfigurations/internal/internal.go +++ b/client-go/applyconfigurations/internal/internal.go @@ -994,6 +994,9 @@ var schemaYAML = typed.YAMLObject(`types: type: scalar: string default: "" + - name: state + type: + scalar: string - name: com.github.ironcore-dev.ironcore.api.networking.v1alpha1.NetworkPolicy map: fields: diff --git a/client-go/applyconfigurations/networking/v1alpha1/networkpeeringstatus.go b/client-go/applyconfigurations/networking/v1alpha1/networkpeeringstatus.go index 80f674b9b..b89d0e54c 100644 --- a/client-go/applyconfigurations/networking/v1alpha1/networkpeeringstatus.go +++ b/client-go/applyconfigurations/networking/v1alpha1/networkpeeringstatus.go @@ -5,10 +5,15 @@ package v1alpha1 +import ( + v1alpha1 "github.com/ironcore-dev/ironcore/api/networking/v1alpha1" +) + // NetworkPeeringStatusApplyConfiguration represents an declarative configuration of the NetworkPeeringStatus type for use // with apply. type NetworkPeeringStatusApplyConfiguration struct { - Name *string `json:"name,omitempty"` + Name *string `json:"name,omitempty"` + State *v1alpha1.NetworkPeeringState `json:"state,omitempty"` } // NetworkPeeringStatusApplyConfiguration constructs an declarative configuration of the NetworkPeeringStatus type for use with @@ -24,3 +29,11 @@ func (b *NetworkPeeringStatusApplyConfiguration) WithName(value string) *Network b.Name = &value return b } + +// WithState sets the State field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the State field is set to the value of the last call. +func (b *NetworkPeeringStatusApplyConfiguration) WithState(value v1alpha1.NetworkPeeringState) *NetworkPeeringStatusApplyConfiguration { + b.State = &value + return b +} diff --git a/client-go/openapi/zz_generated.openapi.go b/client-go/openapi/zz_generated.openapi.go index c76580466..e8fb61558 100644 --- a/client-go/openapi/zz_generated.openapi.go +++ b/client-go/openapi/zz_generated.openapi.go @@ -3708,6 +3708,13 @@ func schema_ironcore_api_networking_v1alpha1_NetworkPeeringStatus(ref common.Ref Format: "", }, }, + "state": { + SchemaProps: spec.SchemaProps{ + Description: "State represents the network peering state", + Type: []string{"string"}, + Format: "", + }, + }, }, Required: []string{"name"}, }, diff --git a/cmd/ironcore-controller-manager/main.go b/cmd/ironcore-controller-manager/main.go index 8017bdd8c..b5ba22219 100644 --- a/cmd/ironcore-controller-manager/main.go +++ b/cmd/ironcore-controller-manager/main.go @@ -76,6 +76,7 @@ const ( loadBalancerController = "loadbalancer" loadBalancerEphemeralPrefixController = "loadbalancerephemeralprefix" networkProtectionController = "networkprotection" + networkPeeringController = "networkpeering" networkReleaseController = "networkrelease" networkInterfaceEphemeralPrefixController = "networkinterfaceephemeralprefix" networkInterfaceEphemeralVirtualIPController = "networkinterfaceephemeralvirtualip" @@ -341,6 +342,15 @@ func main() { } } + if controllers.Enabled(networkPeeringController) { + if err := (&networkingcontrollers.NetworkPeeringReconciler{ + Client: mgr.GetClient(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "NetworkPeering") + os.Exit(1) + } + } + if controllers.Enabled(networkReleaseController) { if err := (&networkingcontrollers.NetworkReleaseReconciler{ Client: mgr.GetClient(), @@ -523,6 +533,13 @@ func main() { } } + if controllers.AnyEnabled(networkProtectionController) { + if err := networkingclient.SetupNetworkSpecPeeringClaimRefNamesFieldIndexer(ctx, mgr.GetFieldIndexer()); err != nil { + setupLog.Error(err, "unable to setup field indexer", "field", networkingclient.NetworkSpecPeeringClaimRefNamesField) + os.Exit(1) + } + } + if controllers.AnyEnabled(networkInterfaceEphemeralPrefixController) { if err := networkingclient.SetupNetworkInterfacePrefixNamesFieldIndexer(ctx, mgr.GetFieldIndexer()); err != nil { setupLog.Error(err, "unable to setup field indexer", "field", networkingclient.NetworkInterfacePrefixNamesField) diff --git a/internal/apis/networking/network_type.go b/internal/apis/networking/network_type.go index 32ae633c6..e2d26b131 100644 --- a/internal/apis/networking/network_type.go +++ b/internal/apis/networking/network_type.go @@ -68,10 +68,22 @@ type NetworkStatus struct { // +enum type NetworkState string +// NetworkPeeringState is the state a NetworkPeering can be in. +type NetworkPeeringState string + +const ( + // NetworkPeeringStatePending signals that the network peering is not applied. + NetworkPeeringStatePending NetworkPeeringState = "Pending" + // NetworkPeeringStateApplied signals that the network peering is applied. + NetworkPeeringStateApplied NetworkPeeringState = "Applied" +) + // NetworkPeeringStatus is the status of a network peering. type NetworkPeeringStatus struct { // Name is the name of the network peering. Name string + // State represents the network peering state + State NetworkPeeringState } const ( diff --git a/internal/apis/networking/v1alpha1/zz_generated.conversion.go b/internal/apis/networking/v1alpha1/zz_generated.conversion.go index 02d892714..6231d2651 100644 --- a/internal/apis/networking/v1alpha1/zz_generated.conversion.go +++ b/internal/apis/networking/v1alpha1/zz_generated.conversion.go @@ -1169,6 +1169,7 @@ func Convert_networking_NetworkPeeringNetworkRef_To_v1alpha1_NetworkPeeringNetwo func autoConvert_v1alpha1_NetworkPeeringStatus_To_networking_NetworkPeeringStatus(in *v1alpha1.NetworkPeeringStatus, out *networking.NetworkPeeringStatus, s conversion.Scope) error { out.Name = in.Name + out.State = networking.NetworkPeeringState(in.State) return nil } @@ -1179,6 +1180,7 @@ func Convert_v1alpha1_NetworkPeeringStatus_To_networking_NetworkPeeringStatus(in func autoConvert_networking_NetworkPeeringStatus_To_v1alpha1_NetworkPeeringStatus(in *networking.NetworkPeeringStatus, out *v1alpha1.NetworkPeeringStatus, s conversion.Scope) error { out.Name = in.Name + out.State = v1alpha1.NetworkPeeringState(in.State) return nil } diff --git a/internal/client/networking/network.go b/internal/client/networking/network.go new file mode 100644 index 000000000..738947200 --- /dev/null +++ b/internal/client/networking/network.go @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package networking + +import ( + "context" + + "github.com/ironcore-dev/ironcore/api/networking/v1alpha1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +const NetworkSpecPeeringClaimRefNamesField = "network-spec-peering-claim-ref-names" + +func SetupNetworkSpecPeeringClaimRefNamesFieldIndexer(ctx context.Context, indexer client.FieldIndexer) error { + return indexer.IndexField(ctx, &v1alpha1.Network{}, NetworkSpecPeeringClaimRefNamesField, func(obj client.Object) []string { + network := obj.(*v1alpha1.Network) + peeringClaimRefNames := make([]string, 0, len(network.Spec.PeeringClaimRefs)) + for _, peeringClaimRef := range network.Spec.PeeringClaimRefs { + peeringClaimRefNames = append(peeringClaimRefNames, peeringClaimRef.Name) + } + + if len(peeringClaimRefNames) == 0 { + return []string{""} + } + return peeringClaimRefNames + }) +} diff --git a/internal/controllers/networking/network_peering_controller.go b/internal/controllers/networking/network_peering_controller.go new file mode 100644 index 000000000..2b9f41dd6 --- /dev/null +++ b/internal/controllers/networking/network_peering_controller.go @@ -0,0 +1,224 @@ +// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package networking + +import ( + "context" + "fmt" + + "github.com/go-logr/logr" + networkingv1alpha1 "github.com/ironcore-dev/ironcore/api/networking/v1alpha1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/util/sets" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/predicate" +) + +type NetworkPeeringReconciler struct { + client.Client +} + +//+kubebuilder:rbac:groups=networking.ironcore.dev,resources=networks,verbs=get;list;watch;update;patch +//+kubebuilder:rbac:groups=networking.ironcore.dev,resources=networks/status,verbs=get;update;patch + +func (r *NetworkPeeringReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + log := ctrl.LoggerFrom(ctx) + network := &networkingv1alpha1.Network{} + if err := r.Get(ctx, req.NamespacedName, network); err != nil { + return ctrl.Result{}, client.IgnoreNotFound(err) + } + + return r.reconcileExists(ctx, log, network) +} + +func (r *NetworkPeeringReconciler) reconcileExists(ctx context.Context, log logr.Logger, network *networkingv1alpha1.Network) (ctrl.Result, error) { + if !network.DeletionTimestamp.IsZero() { + return ctrl.Result{}, nil + } + + return r.reconcile(ctx, log, network) +} + +func (r *NetworkPeeringReconciler) reconcile(ctx context.Context, log logr.Logger, network *networkingv1alpha1.Network) (ctrl.Result, error) { + log.V(1).Info("Reconcile") + + var peeringClaimRefs []networkingv1alpha1.NetworkPeeringClaimRef + var peeringNames []string + + for _, peering := range network.Spec.Peerings { + peeringClaimRef, err := r.reconcilePeering(ctx, log, network, peering) + + if err != nil { + return ctrl.Result{}, fmt.Errorf("[network peering %s] %w", peering.Name, err) + } + + if peeringClaimRef != (networkingv1alpha1.NetworkPeeringClaimRef{}) { + peeringClaimRefs = append(peeringClaimRefs, peeringClaimRef) + } + + if peering.Name != "" { + peeringNames = append(peeringNames, peering.Name) + } + } + + if len(peeringClaimRefs) > 0 { + log.V(1).Info("Peering claim refs require network spec update") + if err := r.updateSpec(ctx, log, network, peeringClaimRefs); err != nil { + return ctrl.Result{}, fmt.Errorf("error updating network spec: %w", err) + } + } + + if len(peeringNames) > 0 { + log.V(1).Info("Network peering status require network status update") + if err := r.updateStatus(ctx, log, network, peeringNames); err != nil { + return ctrl.Result{}, fmt.Errorf("error updating network status: %w", err) + } + } + + log.V(1).Info("Reconciled") + return ctrl.Result{}, nil +} + +func (r *NetworkPeeringReconciler) updateStatus( + ctx context.Context, + log logr.Logger, + network *networkingv1alpha1.Network, + peeringNames []string, +) error { + base := network.DeepCopy() + newStatusPeerings := make([]networkingv1alpha1.NetworkPeeringStatus, 0, len(peeringNames)) + for _, name := range peeringNames { + newStatusPeerings = append(newStatusPeerings, networkingv1alpha1.NetworkPeeringStatus{ + Name: name, + State: networkingv1alpha1.NetworkPeeringStatePending, + }) + } + network.Status.Peerings = newStatusPeerings + + log.V(1).Info("Updating network status peerings", "", network.Status.Peerings) + if err := r.Status().Patch(ctx, network, client.StrategicMergeFrom(base)); err != nil { + return fmt.Errorf("error updating network status peerings: %w", err) + } + log.V(1).Info("Updated network status peerings") + + return nil +} + +func (r *NetworkPeeringReconciler) updateSpec( + ctx context.Context, + log logr.Logger, + network *networkingv1alpha1.Network, + peeringClaimRefs []networkingv1alpha1.NetworkPeeringClaimRef, +) error { + base := network.DeepCopy() + network.Spec.PeeringClaimRefs = peeringClaimRefs + log.V(1).Info("Updating network spec incoming peerings") + if err := r.Patch(ctx, network, client.StrategicMergeFrom(base)); err != nil { + return fmt.Errorf("error updating network spec incoming peerings: %w", err) + } + + log.V(1).Info("Updated network spec incoming peerings") + return nil +} + +func (r *NetworkPeeringReconciler) reconcilePeering( + ctx context.Context, + log logr.Logger, + network *networkingv1alpha1.Network, + peering networkingv1alpha1.NetworkPeering, +) (networkingv1alpha1.NetworkPeeringClaimRef, error) { + networkKey := client.ObjectKeyFromObject(network) + + targetNetwork := &networkingv1alpha1.Network{} + targetNetworkRef := peering.NetworkRef + targetNetworkNamespace := targetNetworkRef.Namespace + if targetNetworkNamespace == "" { + targetNetworkNamespace = network.Namespace + } + targetNetworkKey := client.ObjectKey{Namespace: targetNetworkNamespace, Name: targetNetworkRef.Name} + log = log.WithValues("TargetNetworkKey", targetNetworkKey) + + log.V(1).Info("Getting target network") + if err := r.Get(ctx, targetNetworkKey, targetNetwork); err != nil { + if !apierrors.IsNotFound(err) { + return networkingv1alpha1.NetworkPeeringClaimRef{}, fmt.Errorf("error getting target network %s: %w", targetNetworkKey, err) + } + + log.V(1).Info("Target network not found") + return networkingv1alpha1.NetworkPeeringClaimRef{}, nil + } + + for _, targetPeering := range targetNetwork.Spec.Peerings { + targetPeeringNetworkRef := targetPeering.NetworkRef + targetPeeringNetworkNamespace := targetPeeringNetworkRef.Namespace + if targetPeeringNetworkNamespace == "" { + targetPeeringNetworkNamespace = targetNetwork.Namespace + } + targetPeeringNetworkKey := client.ObjectKey{Namespace: targetPeeringNetworkNamespace, Name: targetPeeringNetworkRef.Name} + + if targetPeeringNetworkKey != networkKey { + continue + } + + if targetNetwork.Status.State != networkingv1alpha1.NetworkStateAvailable { + log.V(1).Info("Target network is not available yet") + return networkingv1alpha1.NetworkPeeringClaimRef{}, nil + } + + log.V(1).Info("Target network peering matches") + peeringClaimRef := networkingv1alpha1.NetworkPeeringClaimRef{ + Namespace: targetNetwork.Namespace, + Name: targetNetwork.Name, + UID: targetNetwork.UID, + } + + return peeringClaimRef, nil + } + + log.V(1).Info("No matching target peering found") + return networkingv1alpha1.NetworkPeeringClaimRef{}, nil +} + +func (r *NetworkPeeringReconciler) enqueuePeeringReferencedNetworks() handler.EventHandler { + return handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []ctrl.Request { + network := obj.(*networkingv1alpha1.Network) + reqs := sets.New[ctrl.Request]() + for _, peering := range network.Spec.Peerings { + ref := peering.NetworkRef + refNamespace := ref.Namespace + if refNamespace == "" { + refNamespace = network.Namespace + } + + refKey := client.ObjectKey{Namespace: refNamespace, Name: ref.Name} + reqs.Insert(ctrl.Request{NamespacedName: refKey}) + } + return reqs.UnsortedList() + }) +} + +func (r *NetworkPeeringReconciler) networkStateAvailablePredicate() predicate.Predicate { + return predicate.NewPredicateFuncs(func(obj client.Object) bool { + network := obj.(*networkingv1alpha1.Network) + return network.Status.State == networkingv1alpha1.NetworkStateAvailable + }) +} + +func (r *NetworkPeeringReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + Named("networkpeering"). + For( + &networkingv1alpha1.Network{}, + builder.WithPredicates(r.networkStateAvailablePredicate()), + ). + Watches( + &networkingv1alpha1.Network{}, + r.enqueuePeeringReferencedNetworks(), + builder.WithPredicates(r.networkStateAvailablePredicate()), + ). + Complete(r) +} diff --git a/internal/controllers/networking/network_peering_controller_test.go b/internal/controllers/networking/network_peering_controller_test.go new file mode 100644 index 000000000..5f98e581c --- /dev/null +++ b/internal/controllers/networking/network_peering_controller_test.go @@ -0,0 +1,553 @@ +// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package networking + +import ( + networkingv1alpha1 "github.com/ironcore-dev/ironcore/api/networking/v1alpha1" + . "github.com/ironcore-dev/ironcore/utils/testing" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + . "sigs.k8s.io/controller-runtime/pkg/envtest/komega" +) + +var _ = Describe("NetworkPeeringController", func() { + ns := SetupNamespace(&k8sClient) + ns1 := SetupNamespace(&k8sClient) + + It("should peer networks in the same namespace referencing a single parent network", func(ctx SpecContext) { + By("creating a network network-1") + network1 := &networkingv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns.Name, + Name: "network-1", + }, + Spec: networkingv1alpha1.NetworkSpec{ + Peerings: []networkingv1alpha1.NetworkPeering{ + { + Name: "peering-1", + NetworkRef: networkingv1alpha1.NetworkPeeringNetworkRef{ + Name: "network-2", + Namespace: ns.Name, + }, + }, + { + Name: "peering-2", + NetworkRef: networkingv1alpha1.NetworkPeeringNetworkRef{ + Name: "network-3", + }, + }, + { + Name: "peering-3", + NetworkRef: networkingv1alpha1.NetworkPeeringNetworkRef{ + Name: "network-4", + Namespace: ns.Name, + }, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, network1)).To(Succeed()) + + By("creating a network network-2") + network2 := &networkingv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns.Name, + Name: "network-2", + }, + Spec: networkingv1alpha1.NetworkSpec{ + Peerings: []networkingv1alpha1.NetworkPeering{ + { + Name: "peering-2", + NetworkRef: networkingv1alpha1.NetworkPeeringNetworkRef{ + Name: "network-1", + Namespace: ns.Name, + }, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, network2)).To(Succeed()) + + By("creating a network network-3") + network3 := &networkingv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns.Name, + Name: "network-3", + }, + Spec: networkingv1alpha1.NetworkSpec{ + Peerings: []networkingv1alpha1.NetworkPeering{ + { + Name: "peering-3", + NetworkRef: networkingv1alpha1.NetworkPeeringNetworkRef{ + Name: "network-1", + Namespace: ns.Name, + }, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, network3)).To(Succeed()) + + By("creating a network network-4") + network4 := &networkingv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns.Name, + Name: "network-4", + }, + Spec: networkingv1alpha1.NetworkSpec{ + Peerings: []networkingv1alpha1.NetworkPeering{ + { + Name: "peering-4", + NetworkRef: networkingv1alpha1.NetworkPeeringNetworkRef{ + Name: "network-1", + Namespace: ns.Name, + }, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, network4)).To(Succeed()) + + By("patching networks as available") + baseNetwork1 := network1.DeepCopy() + network1.Status.State = networkingv1alpha1.NetworkStateAvailable + Expect(k8sClient.Status().Patch(ctx, network1, client.MergeFrom(baseNetwork1))).To(Succeed()) + + baseNetwork2 := network2.DeepCopy() + network2.Status.State = networkingv1alpha1.NetworkStateAvailable + Expect(k8sClient.Status().Patch(ctx, network2, client.MergeFrom(baseNetwork2))).To(Succeed()) + + baseNetwork3 := network3.DeepCopy() + network3.Status.State = networkingv1alpha1.NetworkStateAvailable + Expect(k8sClient.Status().Patch(ctx, network3, client.MergeFrom(baseNetwork3))).To(Succeed()) + + baseNetwork4 := network4.DeepCopy() + network4.Status.State = networkingv1alpha1.NetworkStateAvailable + Expect(k8sClient.Status().Patch(ctx, network4, client.MergeFrom(baseNetwork4))).To(Succeed()) + + By("waiting for networks to reference each other") + Eventually(Object(network1)). + Should(SatisfyAll( + HaveField("Spec.PeeringClaimRefs", ConsistOf(networkingv1alpha1.NetworkPeeringClaimRef{ + Namespace: network2.Namespace, + Name: network2.Name, + UID: network2.UID, + }, networkingv1alpha1.NetworkPeeringClaimRef{ + Namespace: network3.Namespace, + Name: network3.Name, + UID: network3.UID, + }, networkingv1alpha1.NetworkPeeringClaimRef{ + Namespace: network4.Namespace, + Name: network4.Name, + UID: network4.UID, + })), + HaveField("Status.State", Equal(networkingv1alpha1.NetworkStateAvailable)), + HaveField("Status.Peerings", ConsistOf(networkingv1alpha1.NetworkPeeringStatus{ + Name: network1.Spec.Peerings[0].Name, + State: networkingv1alpha1.NetworkPeeringStatePending, + }, networkingv1alpha1.NetworkPeeringStatus{ + Name: network1.Spec.Peerings[1].Name, + State: networkingv1alpha1.NetworkPeeringStatePending, + }, networkingv1alpha1.NetworkPeeringStatus{ + Name: network1.Spec.Peerings[2].Name, + State: networkingv1alpha1.NetworkPeeringStatePending, + })), + )) + + Eventually(Object(network2)). + Should(SatisfyAll( + HaveField("Spec.PeeringClaimRefs", ConsistOf(networkingv1alpha1.NetworkPeeringClaimRef{ + Namespace: network1.Namespace, + Name: network1.Name, + UID: network1.UID, + })), + HaveField("Status.State", Equal(networkingv1alpha1.NetworkStateAvailable)), + HaveField("Status.Peerings", ConsistOf(networkingv1alpha1.NetworkPeeringStatus{ + Name: network2.Spec.Peerings[0].Name, + State: networkingv1alpha1.NetworkPeeringStatePending, + })), + )) + + Eventually(Object(network3)). + Should(SatisfyAll( + HaveField("Spec.PeeringClaimRefs", ConsistOf(networkingv1alpha1.NetworkPeeringClaimRef{ + Namespace: network1.Namespace, + Name: network1.Name, + UID: network1.UID, + })), + HaveField("Status.State", Equal(networkingv1alpha1.NetworkStateAvailable)), + HaveField("Status.Peerings", ConsistOf(networkingv1alpha1.NetworkPeeringStatus{ + Name: network3.Spec.Peerings[0].Name, + State: networkingv1alpha1.NetworkPeeringStatePending, + })), + )) + + Eventually(Object(network4)). + Should(SatisfyAll( + HaveField("Spec.PeeringClaimRefs", ConsistOf(networkingv1alpha1.NetworkPeeringClaimRef{ + Namespace: network1.Namespace, + Name: network1.Name, + UID: network1.UID, + })), + HaveField("Status.State", Equal(networkingv1alpha1.NetworkStateAvailable)), + HaveField("Status.Peerings", ConsistOf(networkingv1alpha1.NetworkPeeringStatus{ + Name: network4.Spec.Peerings[0].Name, + State: networkingv1alpha1.NetworkPeeringStatePending, + })), + )) + + By("deleting the networks") + Expect(k8sClient.Delete(ctx, network1)).To(Succeed()) + Expect(k8sClient.Delete(ctx, network2)).To(Succeed()) + Expect(k8sClient.Delete(ctx, network3)).To(Succeed()) + Expect(k8sClient.Delete(ctx, network4)).To(Succeed()) + + By("waiting for networks to be gone") + Eventually(Get(network1)).Should(Satisfy(apierrors.IsNotFound)) + Eventually(Get(network2)).Should(Satisfy(apierrors.IsNotFound)) + Eventually(Get(network3)).Should(Satisfy(apierrors.IsNotFound)) + Eventually(Get(network4)).Should(Satisfy(apierrors.IsNotFound)) + }) + + It("should peer two networks from different namespaces if they reference each other correctly", func(ctx SpecContext) { + By("creating a network network-1") + network1 := &networkingv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns.Name, + Name: "network-1", + }, + Spec: networkingv1alpha1.NetworkSpec{ + Peerings: []networkingv1alpha1.NetworkPeering{ + { + Name: "peering-1", + NetworkRef: networkingv1alpha1.NetworkPeeringNetworkRef{ + Name: "network-2", + Namespace: ns1.Name, + }, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, network1)).To(Succeed()) + + By("creating a network network-2") + network2 := &networkingv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns1.Name, + Name: "network-2", + }, + Spec: networkingv1alpha1.NetworkSpec{ + Peerings: []networkingv1alpha1.NetworkPeering{ + { + Name: "peering-2", + NetworkRef: networkingv1alpha1.NetworkPeeringNetworkRef{ + Name: "network-1", + Namespace: ns.Name, + }, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, network2)).To(Succeed()) + + By("patching networks as available") + baseNetwork1 := network1.DeepCopy() + network1.Status.State = networkingv1alpha1.NetworkStateAvailable + Expect(k8sClient.Status().Patch(ctx, network1, client.MergeFrom(baseNetwork1))).To(Succeed()) + + baseNetwork2 := network2.DeepCopy() + network2.Status.State = networkingv1alpha1.NetworkStateAvailable + Expect(k8sClient.Status().Patch(ctx, network2, client.MergeFrom(baseNetwork2))).To(Succeed()) + + By("waiting for networks to reference each other") + Eventually(Object(network1)). + Should(SatisfyAll( + HaveField("Spec.PeeringClaimRefs", ConsistOf(networkingv1alpha1.NetworkPeeringClaimRef{ + Namespace: network2.Namespace, + Name: network2.Name, + UID: network2.UID, + })), + HaveField("Status.State", Equal(networkingv1alpha1.NetworkStateAvailable)), + HaveField("Status.Peerings", ConsistOf(networkingv1alpha1.NetworkPeeringStatus{ + Name: network1.Spec.Peerings[0].Name, + State: networkingv1alpha1.NetworkPeeringStatePending, + })), + )) + + Eventually(Object(network2)). + Should(SatisfyAll( + HaveField("Spec.PeeringClaimRefs", ConsistOf(networkingv1alpha1.NetworkPeeringClaimRef{ + Namespace: network1.Namespace, + Name: network1.Name, + UID: network1.UID, + })), + HaveField("Status.State", Equal(networkingv1alpha1.NetworkStateAvailable)), + HaveField("Status.Peerings", ConsistOf(networkingv1alpha1.NetworkPeeringStatus{ + Name: network2.Spec.Peerings[0].Name, + State: networkingv1alpha1.NetworkPeeringStatePending, + })), + )) + + By("deleting the networks") + Expect(k8sClient.Delete(ctx, network1)).To(Succeed()) + Expect(k8sClient.Delete(ctx, network2)).To(Succeed()) + + By("waiting for networks to be gone") + Eventually(Get(network1)).Should(Satisfy(apierrors.IsNotFound)) + Eventually(Get(network2)).Should(Satisfy(apierrors.IsNotFound)) + }) + + It("should not peer two networks if they dont exactly reference each other", func(ctx SpecContext) { + By("creating a network network-1") + network1 := &networkingv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns.Name, + Name: "network-1", + }, + Spec: networkingv1alpha1.NetworkSpec{ + Peerings: []networkingv1alpha1.NetworkPeering{ + { + Name: "peering-1", + NetworkRef: networkingv1alpha1.NetworkPeeringNetworkRef{ + Name: "network-2", + Namespace: ns1.Name, + }, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, network1)).To(Succeed()) + + By("creating a network network-2") + network2 := &networkingv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns.Name, + Name: "network-2", + }, + Spec: networkingv1alpha1.NetworkSpec{ + Peerings: []networkingv1alpha1.NetworkPeering{ + { + Name: "peering-2", + NetworkRef: networkingv1alpha1.NetworkPeeringNetworkRef{ + Name: "network-other", + Namespace: ns.Name, + }, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, network2)).To(Succeed()) + + By("patching networks as available") + baseNetwork1 := network1.DeepCopy() + network1.Status.State = networkingv1alpha1.NetworkStateAvailable + Expect(k8sClient.Status().Patch(ctx, network1, client.MergeFrom(baseNetwork1))).To(Succeed()) + + baseNetwork2 := network2.DeepCopy() + network2.Status.State = networkingv1alpha1.NetworkStateAvailable + Expect(k8sClient.Status().Patch(ctx, network2, client.MergeFrom(baseNetwork2))).To(Succeed()) + + By("ensuring both networks do not get peered") + Eventually(Object(network1)). + Should(SatisfyAll( + HaveField("Spec.PeeringClaimRefs", BeEmpty()), + HaveField("Status.State", Equal(networkingv1alpha1.NetworkStateAvailable)), + HaveField("Status.Peerings", ConsistOf(networkingv1alpha1.NetworkPeeringStatus{ + Name: network1.Spec.Peerings[0].Name, + State: networkingv1alpha1.NetworkPeeringStatePending, + })), + )) + + Eventually(Object(network2)). + Should(SatisfyAll( + HaveField("Spec.PeeringClaimRefs", BeEmpty()), + HaveField("Status.State", Equal(networkingv1alpha1.NetworkStateAvailable)), + HaveField("Status.Peerings", ConsistOf(networkingv1alpha1.NetworkPeeringStatus{ + Name: network2.Spec.Peerings[0].Name, + State: networkingv1alpha1.NetworkPeeringStatePending, + })), + )) + + By("deleting the networks") + Expect(k8sClient.Delete(ctx, network1)).To(Succeed()) + Expect(k8sClient.Delete(ctx, network2)).To(Succeed()) + + By("waiting for networks to be gone") + Eventually(Get(network1)).Should(Satisfy(apierrors.IsNotFound)) + Eventually(Get(network2)).Should(Satisfy(apierrors.IsNotFound)) + }) + + It("should peer networks in the same namespace referencing each other", func(ctx SpecContext) { + By("creating a network network-1") + network1 := &networkingv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns.Name, + Name: "network-1", + }, + Spec: networkingv1alpha1.NetworkSpec{ + Peerings: []networkingv1alpha1.NetworkPeering{ + { + Name: "peering-1", + NetworkRef: networkingv1alpha1.NetworkPeeringNetworkRef{ + Name: "network-2", + Namespace: ns.Name, + }, + }, + { + Name: "peering-2", + NetworkRef: networkingv1alpha1.NetworkPeeringNetworkRef{ + Name: "network-3", + Namespace: ns.Name, + }, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, network1)).To(Succeed()) + + By("creating a network network-2") + network2 := &networkingv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns.Name, + Name: "network-2", + }, + Spec: networkingv1alpha1.NetworkSpec{ + Peerings: []networkingv1alpha1.NetworkPeering{ + { + Name: "peering-1", + NetworkRef: networkingv1alpha1.NetworkPeeringNetworkRef{ + Name: "network-1", + Namespace: ns.Name, + }, + }, + { + Name: "peering-2", + NetworkRef: networkingv1alpha1.NetworkPeeringNetworkRef{ + Name: "network-3", + Namespace: ns.Name, + }, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, network2)).To(Succeed()) + + By("creating a network network-3") + network3 := &networkingv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns.Name, + Name: "network-3", + }, + Spec: networkingv1alpha1.NetworkSpec{ + Peerings: []networkingv1alpha1.NetworkPeering{ + { + Name: "peering-1", + NetworkRef: networkingv1alpha1.NetworkPeeringNetworkRef{ + Name: "network-1", + Namespace: ns.Name, + }, + }, + { + Name: "peering-2", + NetworkRef: networkingv1alpha1.NetworkPeeringNetworkRef{ + Name: "network-2", + Namespace: ns.Name, + }, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, network3)).To(Succeed()) + + By("patching networks as available") + baseNetwork1 := network1.DeepCopy() + network1.Status.State = networkingv1alpha1.NetworkStateAvailable + Expect(k8sClient.Status().Patch(ctx, network1, client.MergeFrom(baseNetwork1))).To(Succeed()) + + baseNetwork2 := network2.DeepCopy() + network2.Status.State = networkingv1alpha1.NetworkStateAvailable + Expect(k8sClient.Status().Patch(ctx, network2, client.MergeFrom(baseNetwork2))).To(Succeed()) + + baseNetwork3 := network3.DeepCopy() + network3.Status.State = networkingv1alpha1.NetworkStateAvailable + Expect(k8sClient.Status().Patch(ctx, network3, client.MergeFrom(baseNetwork3))).To(Succeed()) + + By("waiting for networks to reference each other") + Eventually(Object(network1)). + Should(SatisfyAll( + HaveField("Spec.PeeringClaimRefs", ConsistOf(networkingv1alpha1.NetworkPeeringClaimRef{ + Namespace: network2.Namespace, + Name: network2.Name, + UID: network2.UID, + }, networkingv1alpha1.NetworkPeeringClaimRef{ + Namespace: network3.Namespace, + Name: network3.Name, + UID: network3.UID, + })), + HaveField("Status.State", Equal(networkingv1alpha1.NetworkStateAvailable)), + HaveField("Status.Peerings", ConsistOf(networkingv1alpha1.NetworkPeeringStatus{ + Name: network1.Spec.Peerings[0].Name, + State: networkingv1alpha1.NetworkPeeringStatePending, + }, networkingv1alpha1.NetworkPeeringStatus{ + Name: network1.Spec.Peerings[1].Name, + State: networkingv1alpha1.NetworkPeeringStatePending, + })), + )) + + Eventually(Object(network2)). + Should(SatisfyAll( + HaveField("Spec.PeeringClaimRefs", ConsistOf(networkingv1alpha1.NetworkPeeringClaimRef{ + Namespace: network1.Namespace, + Name: network1.Name, + UID: network1.UID, + }, networkingv1alpha1.NetworkPeeringClaimRef{ + Namespace: network3.Namespace, + Name: network3.Name, + UID: network3.UID, + })), + HaveField("Status.State", Equal(networkingv1alpha1.NetworkStateAvailable)), + HaveField("Status.Peerings", ConsistOf(networkingv1alpha1.NetworkPeeringStatus{ + Name: network2.Spec.Peerings[0].Name, + State: networkingv1alpha1.NetworkPeeringStatePending, + }, networkingv1alpha1.NetworkPeeringStatus{ + Name: network2.Spec.Peerings[1].Name, + State: networkingv1alpha1.NetworkPeeringStatePending, + })), + )) + + Eventually(Object(network3)). + Should(SatisfyAll( + HaveField("Spec.PeeringClaimRefs", ConsistOf(networkingv1alpha1.NetworkPeeringClaimRef{ + Namespace: network1.Namespace, + Name: network1.Name, + UID: network1.UID, + }, networkingv1alpha1.NetworkPeeringClaimRef{ + Namespace: network2.Namespace, + Name: network2.Name, + UID: network2.UID, + })), + HaveField("Status.State", Equal(networkingv1alpha1.NetworkStateAvailable)), + HaveField("Status.Peerings", ConsistOf(networkingv1alpha1.NetworkPeeringStatus{ + Name: network3.Spec.Peerings[0].Name, + State: networkingv1alpha1.NetworkPeeringStatePending, + }, networkingv1alpha1.NetworkPeeringStatus{ + Name: network3.Spec.Peerings[1].Name, + State: networkingv1alpha1.NetworkPeeringStatePending, + })), + )) + + By("deleting the networks") + Expect(k8sClient.Delete(ctx, network1)).To(Succeed()) + Expect(k8sClient.Delete(ctx, network2)).To(Succeed()) + Expect(k8sClient.Delete(ctx, network3)).To(Succeed()) + + By("waiting for networks to be gone") + Eventually(Get(network1)).Should(Satisfy(apierrors.IsNotFound)) + Eventually(Get(network2)).Should(Satisfy(apierrors.IsNotFound)) + Eventually(Get(network3)).Should(Satisfy(apierrors.IsNotFound)) + }) +}) diff --git a/internal/controllers/networking/network_protection_controller.go b/internal/controllers/networking/network_protection_controller.go index 9c1cf267d..ec23a1640 100644 --- a/internal/controllers/networking/network_protection_controller.go +++ b/internal/controllers/networking/network_protection_controller.go @@ -141,6 +141,10 @@ func (r *NetworkProtectionReconciler) isNetworkInUse(ctx context.Context, log lo Type: &networkingv1alpha1.NATGateway{}, Field: networking.NATGatewayNetworkNameField, }, + { + Type: &networkingv1alpha1.Network{}, + Field: networking.NetworkSpecPeeringClaimRefNamesField, + }, } for _, typeAndField := range typesAndFields { @@ -148,7 +152,7 @@ func (r *NetworkProtectionReconciler) isNetworkInUse(ctx context.Context, log lo if err != nil { return false, fmt.Errorf("error checking if network is in use by %T: %w", typeAndField.Type, err) } - if err != nil || ok { + if ok { return ok, err } } @@ -172,6 +176,10 @@ func (r *NetworkProtectionReconciler) SetupWithManager(mgr ctrl.Manager) error { &networkingv1alpha1.NATGateway{}, r.enqueueByNATGateway(), ). + Watches( + &networkingv1alpha1.Network{}, + r.enqueueByPeeredNetwork(), + ). Complete(r) } @@ -219,3 +227,37 @@ func (r *NetworkProtectionReconciler) enqueueByNATGateway() handler.EventHandler return res }) } + +func (r *NetworkProtectionReconciler) enqueueByPeeredNetwork() handler.EventHandler { + return handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []ctrl.Request { + network := obj.(*networkingv1alpha1.Network) + log := ctrl.LoggerFrom(ctx) + + networkList := &networkingv1alpha1.NetworkList{} + if err := r.List(ctx, networkList); err != nil { + log.Error(err, "Error listing networks") + return nil + } + + var res []ctrl.Request + for _, targetNetwork := range networkList.Items { + var found bool + for _, claimRef := range targetNetwork.Spec.PeeringClaimRefs { + if claimRef.UID == network.UID { + networkKey := types.NamespacedName{ + Namespace: claimRef.Namespace, + Name: claimRef.Name, + } + res = append(res, ctrl.Request{NamespacedName: networkKey}) + found = true + break + } + } + if found { + break + } + } + + return res + }) +} diff --git a/internal/controllers/networking/network_protection_controller_test.go b/internal/controllers/networking/network_protection_controller_test.go index 3d2c9dd1f..46a95a84f 100644 --- a/internal/controllers/networking/network_protection_controller_test.go +++ b/internal/controllers/networking/network_protection_controller_test.go @@ -10,9 +10,11 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" + . "sigs.k8s.io/controller-runtime/pkg/envtest/komega" ) var _ = Describe("NetworkProtectionReconciler", func() { @@ -222,4 +224,103 @@ var _ = Describe("NetworkProtectionReconciler", func() { Expect(client.IgnoreNotFound(err)).To(Succeed()) }).Should(Succeed()) }) + + It("should keep a finalizer if one of two peered networks is deleted", func(ctx SpecContext) { + By("creating a network network-1") + network1 := &networkingv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns.Name, + Name: "network-1", + }, + Spec: networkingv1alpha1.NetworkSpec{ + Peerings: []networkingv1alpha1.NetworkPeering{ + { + Name: "peering-1", + NetworkRef: networkingv1alpha1.NetworkPeeringNetworkRef{ + Name: "network-2", + Namespace: ns.Name, + }, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, network1)).To(Succeed()) + + By("creating a network network-2") + network2 := &networkingv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns.Name, + Name: "network-2", + }, + Spec: networkingv1alpha1.NetworkSpec{ + Peerings: []networkingv1alpha1.NetworkPeering{ + { + Name: "peering-2", + NetworkRef: networkingv1alpha1.NetworkPeeringNetworkRef{ + Name: "network-1", + Namespace: ns.Name, + }, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, network2)).To(Succeed()) + + By("patching networks as available") + baseNetwork1 := network1.DeepCopy() + network1.Status.State = networkingv1alpha1.NetworkStateAvailable + Expect(k8sClient.Status().Patch(ctx, network1, client.MergeFrom(baseNetwork1))).To(Succeed()) + + baseNetwork2 := network2.DeepCopy() + network2.Status.State = networkingv1alpha1.NetworkStateAvailable + Expect(k8sClient.Status().Patch(ctx, network2, client.MergeFrom(baseNetwork2))).To(Succeed()) + + By("ensuring that the network finalizer has been set and waiting for networks to reference each other") + Eventually(Object(network1)). + Should(SatisfyAll( + HaveField("ObjectMeta.Finalizers", ContainElement(networkFinalizer)), + HaveField("Spec.PeeringClaimRefs", ConsistOf(networkingv1alpha1.NetworkPeeringClaimRef{ + Namespace: network2.Namespace, + Name: network2.Name, + UID: network2.UID, + })), + HaveField("Status.State", Equal(networkingv1alpha1.NetworkStateAvailable)), + HaveField("Status.Peerings", ConsistOf(networkingv1alpha1.NetworkPeeringStatus{ + Name: network1.Spec.Peerings[0].Name, + State: networkingv1alpha1.NetworkPeeringStatePending, + })), + )) + + Eventually(Object(network2)). + Should(SatisfyAll( + HaveField("ObjectMeta.Finalizers", ContainElement(networkFinalizer)), + HaveField("Spec.PeeringClaimRefs", ConsistOf(networkingv1alpha1.NetworkPeeringClaimRef{ + Namespace: network1.Namespace, + Name: network1.Name, + UID: network1.UID, + })), + HaveField("Status.State", Equal(networkingv1alpha1.NetworkStateAvailable)), + HaveField("Status.Peerings", ConsistOf(networkingv1alpha1.NetworkPeeringStatus{ + Name: network2.Spec.Peerings[0].Name, + State: networkingv1alpha1.NetworkPeeringStatePending, + })), + )) + + By("deleting the network-1") + Expect(k8sClient.Delete(ctx, network1)).To(Succeed()) + + By("ensuring that the network-1 has a deletion timestamp set and the finalizer still present") + Eventually(Object(network1)).Should(SatisfyAll( + HaveField("ObjectMeta.DeletionTimestamp", Not(BeZero())), + HaveField("ObjectMeta.Finalizers", ContainElement(networkFinalizer)), + )) + + By("deleting the network-2") + Expect(k8sClient.Delete(ctx, network2)).To(Succeed()) + + By("ensuring that the networks has been deleted") + Eventually(Get(network1)).Should(Satisfy(apierrors.IsNotFound)) + Eventually(Get(network2)).Should(Satisfy(apierrors.IsNotFound)) + }) + }) diff --git a/internal/controllers/networking/network_release_controller.go b/internal/controllers/networking/network_release_controller.go index b896870f8..e77a67bf3 100644 --- a/internal/controllers/networking/network_release_controller.go +++ b/internal/controllers/networking/network_release_controller.go @@ -54,7 +54,7 @@ func (r *NetworkReleaseReconciler) filterExistingNetworkPeeringClaimRefs( ) ([]networkingv1alpha1.NetworkPeeringClaimRef, error) { var filtered []networkingv1alpha1.NetworkPeeringClaimRef for _, peeringClaimRef := range network.Spec.PeeringClaimRefs { - ok, err := r.networkPeeringClaimExists(ctx, network, peeringClaimRef) + ok, err := r.networkPeeringClaimExists(ctx, peeringClaimRef) if err != nil { return nil, err } @@ -68,7 +68,6 @@ func (r *NetworkReleaseReconciler) filterExistingNetworkPeeringClaimRefs( func (r *NetworkReleaseReconciler) networkPeeringClaimExists( ctx context.Context, - network *networkingv1alpha1.Network, peeringClaimRef networkingv1alpha1.NetworkPeeringClaimRef, ) (bool, error) { if _, ok := r.AbsenceCache.Get(peeringClaimRef.UID); ok { @@ -81,7 +80,7 @@ func (r *NetworkReleaseReconciler) networkPeeringClaimExists( Kind: "Network", }, } - claimerKey := client.ObjectKey{Namespace: network.Namespace, Name: peeringClaimRef.Name} + claimerKey := client.ObjectKey{Namespace: peeringClaimRef.Namespace, Name: peeringClaimRef.Name} if err := r.APIReader.Get(ctx, claimerKey, claimer); err != nil { if !apierrors.IsNotFound(err) { return false, fmt.Errorf("error getting claiming network %s: %w", peeringClaimRef.Name, err) diff --git a/internal/controllers/networking/suite_test.go b/internal/controllers/networking/suite_test.go index 68747400d..2b74918f6 100644 --- a/internal/controllers/networking/suite_test.go +++ b/internal/controllers/networking/suite_test.go @@ -119,6 +119,7 @@ var _ = BeforeSuite(func() { Expect(networkingclient.SetupNetworkInterfaceVirtualIPNameFieldIndexer(ctx, k8sManager.GetFieldIndexer())).To(Succeed()) Expect(networkingclient.SetupLoadBalancerNetworkNameFieldIndexer(ctx, k8sManager.GetFieldIndexer())).To(Succeed()) Expect(networkingclient.SetupNATGatewayNetworkNameFieldIndexer(ctx, k8sManager.GetFieldIndexer())).To(Succeed()) + Expect(networkingclient.SetupNetworkSpecPeeringClaimRefNamesFieldIndexer(ctx, k8sManager.GetFieldIndexer())).To(Succeed()) Expect(networkingclient.SetupNetworkInterfacePrefixNamesFieldIndexer(ctx, k8sManager.GetFieldIndexer())).To(Succeed()) Expect(networkingclient.SetupLoadBalancerPrefixNamesFieldIndexer(ctx, k8sManager.GetFieldIndexer())).To(Succeed()) @@ -139,6 +140,11 @@ var _ = BeforeSuite(func() { }).SetupWithManager(k8sManager) Expect(err).NotTo(HaveOccurred()) + err = (&NetworkPeeringReconciler{ + Client: k8sManager.GetClient(), + }).SetupWithManager(k8sManager) + Expect(err).NotTo(HaveOccurred()) + Expect((&NetworkReleaseReconciler{ Client: k8sManager.GetClient(), APIReader: k8sManager.GetAPIReader(),