From 1bf1e7fc56699e0cc7d3e81c136d1702559cfbcd Mon Sep 17 00:00:00 2001 From: Kajol Asabe Date: Fri, 8 Mar 2024 13:40:56 +0530 Subject: [PATCH 1/9] Implement network peering in apinetlet --- api/core/v1alpha1/network_types.go | 2 + api/core/v1alpha1/zz_generated.deepcopy.go | 7 +- .../controllers/controllers_suite_test.go | 6 + .../controllers/network_peering_controller.go | 270 ++++++++++ .../network_peering_controller_test.go | 469 ++++++++++++++++++ .../core/v1alpha1/networkspec.go | 13 +- .../applyconfigurations/internal/internal.go | 6 + client-go/openapi/api_violations.report | 1 + client-go/openapi/zz_generated.openapi.go | 15 + cmd/apinetlet/main.go | 10 + internal/apis/core/network_types.go | 2 + .../core/v1alpha1/zz_generated.conversion.go | 2 + internal/apis/core/zz_generated.deepcopy.go | 7 +- 13 files changed, 807 insertions(+), 3 deletions(-) create mode 100644 apinetlet/controllers/network_peering_controller.go create mode 100644 apinetlet/controllers/network_peering_controller_test.go diff --git a/api/core/v1alpha1/network_types.go b/api/core/v1alpha1/network_types.go index 836f1bd2..0259a646 100644 --- a/api/core/v1alpha1/network_types.go +++ b/api/core/v1alpha1/network_types.go @@ -10,6 +10,8 @@ import ( type NetworkSpec struct { // ID is the ID of the network. ID string `json:"id,omitempty"` + // PeeredIDs are the IDs of networks to peer with. + PeeredIDs []string `json:"peeredIDs,omitempty"` } type NetworkStatus struct { diff --git a/api/core/v1alpha1/zz_generated.deepcopy.go b/api/core/v1alpha1/zz_generated.deepcopy.go index 94f1e52a..ecd83c4e 100644 --- a/api/core/v1alpha1/zz_generated.deepcopy.go +++ b/api/core/v1alpha1/zz_generated.deepcopy.go @@ -1176,7 +1176,7 @@ func (in *Network) DeepCopyInto(out *Network) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec + in.Spec.DeepCopyInto(&out.Spec) out.Status = in.Status return } @@ -1525,6 +1525,11 @@ func (in *NetworkList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NetworkSpec) DeepCopyInto(out *NetworkSpec) { *out = *in + if in.PeeredIDs != nil { + in, out := &in.PeeredIDs, &out.PeeredIDs + *out = make([]string, len(*in)) + copy(*out, *in) + } return } diff --git a/apinetlet/controllers/controllers_suite_test.go b/apinetlet/controllers/controllers_suite_test.go index 8f9f13a6..ad0a3c0d 100644 --- a/apinetlet/controllers/controllers_suite_test.go +++ b/apinetlet/controllers/controllers_suite_test.go @@ -154,6 +154,12 @@ func SetupTest(apiNetNamespace *corev1.Namespace) *corev1.Namespace { APINetNamespace: apiNetNamespace.Name, }).SetupWithManager(k8sManager, k8sManager.GetCache())).To(Succeed()) + Expect((&NetworkPeeringReconciler{ + Client: k8sManager.GetClient(), + APINetClient: k8sManager.GetClient(), + APINetNamespace: apiNetNamespace.Name, + }).SetupWithManager(k8sManager, k8sManager.GetCache())).To(Succeed()) + Expect((&NetworkInterfaceReconciler{ Client: k8sManager.GetClient(), APINetClient: k8sManager.GetClient(), diff --git a/apinetlet/controllers/network_peering_controller.go b/apinetlet/controllers/network_peering_controller.go new file mode 100644 index 00000000..7a5906c4 --- /dev/null +++ b/apinetlet/controllers/network_peering_controller.go @@ -0,0 +1,270 @@ +// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package controllers + +import ( + "context" + "fmt" + + "github.com/go-logr/logr" + apinetv1alpha1 "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1" + networkingv1alpha1 "github.com/ironcore-dev/ironcore/api/networking/v1alpha1" + clientutils "github.com/ironcore-dev/ironcore/utils/client" + "github.com/ironcore-dev/ironcore/utils/predicates" + apierrors "k8s.io/apimachinery/pkg/api/errors" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/cache" + "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 + APINetClient client.Client + APINetNamespace string + WatchFilterValue string +} + +//+kubebuilder:rbac:groups="",resources=events,verbs=create;patch +//+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 + +//+cluster=apinet:kubebuilder:rbac:groups=core.apinet.ironcore.dev,resources=networks,verbs=get;list;watch;create;update;patch;delete;deletecollection + +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 + var peeredIDs []string + + for _, peering := range network.Spec.Peerings { + peeringClaimRef, peeringName, peeredID, 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 peeringName != "" { + peeringNames = append(peeringNames, peeringName) + } + if peeredID != "" { + peeredIDs = append(peeredIDs, peeredID) + } + } + + if len(peeringClaimRefs) > 0 { + log.V(1).Info("Peering claim refs require network spec update") + if err := r.updateSpec(ctx, log, network, peeringClaimRefs, peeredIDs); 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, + }) + } + 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, + peeredIDs []string, +) error { + if err := r.updateApinetNetworkSpec(ctx, log, network, peeredIDs); err != nil { + return fmt.Errorf("error updating apinet network spec: %w", err) + } + + 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) updateApinetNetworkSpec( + ctx context.Context, + log logr.Logger, + network *networkingv1alpha1.Network, + peeredIDs []string, +) error { + apinetNetwork := &apinetv1alpha1.Network{} + apinetNetworkKey := client.ObjectKey{Namespace: r.APINetNamespace, Name: string(network.UID)} + if err := r.APINetClient.Get(ctx, apinetNetworkKey, apinetNetwork); err != nil { + return fmt.Errorf("apinet network is not created yet for network: %s \n %w", network.Name, err) + } + + base := apinetNetwork.DeepCopy() + apinetNetwork.Spec.PeeredIDs = peeredIDs + log.V(1).Info("Updating apinet network spec peered ids") + if err := r.APINetClient.Patch(ctx, apinetNetwork, client.StrategicMergeFrom(base)); err != nil { + return fmt.Errorf("error updating apinet network spec peered ids: %w", err) + } + + log.V(1).Info("Updated apinet network spec peered ids") + return nil +} + +func (r *NetworkPeeringReconciler) reconcilePeering( + ctx context.Context, + log logr.Logger, + network *networkingv1alpha1.Network, + peering networkingv1alpha1.NetworkPeering, +) (networkingv1alpha1.NetworkPeeringClaimRef, string, string, 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(2).Info("Getting target network") + if err := r.Get(ctx, targetNetworkKey, targetNetwork); err != nil { + if !apierrors.IsNotFound(err) { + return networkingv1alpha1.NetworkPeeringClaimRef{}, "", "", fmt.Errorf("error getting 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, + } + + log.V(1).Info("Get apinet network for target network") + apinetNetwork := &apinetv1alpha1.Network{} + if err := r.APINetClient.Get(ctx, client.ObjectKey{Namespace: r.APINetNamespace, Name: string(targetNetwork.UID)}, + apinetNetwork); err != nil { + log.V(1).Info("apinet network for target network is not created yet") + return networkingv1alpha1.NetworkPeeringClaimRef{}, "", "", nil + } + return peeringClaimRef, peering.Name, apinetNetwork.Spec.ID, nil + } + + log.V(1).Info("No matching target peering found") + return networkingv1alpha1.NetworkPeeringClaimRef{}, "", "", nil +} + +func (r *NetworkPeeringReconciler) enqueueNetworksHavingPeerings() handler.EventHandler { + return handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []ctrl.Request { + log := ctrl.LoggerFrom(ctx) + networkList := &networkingv1alpha1.NetworkList{} + if err := r.List(ctx, networkList); err != nil { + log.Error(err, "Error listing networks") + return nil + } + + return clientutils.ReconcileRequestsFromObjectStructSlice[*networkingv1alpha1.Network](networkList.Items) + }) +} + +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, apiNetCache cache.Cache) error { + log := ctrl.Log.WithName("networkpeering").WithName("setup") + + return ctrl.NewControllerManagedBy(mgr). + For( + &networkingv1alpha1.Network{}, + builder.WithPredicates( + predicates.ResourceHasFilterLabel(log, r.WatchFilterValue), + predicates.ResourceIsNotExternallyManaged(log), + r.networkStateAvailablePredicate(), + ), + ). + Watches( + &networkingv1alpha1.Network{}, + r.enqueueNetworksHavingPeerings(), + builder.WithPredicates(r.networkStateAvailablePredicate()), + ). + Complete(r) +} diff --git a/apinetlet/controllers/network_peering_controller_test.go b/apinetlet/controllers/network_peering_controller_test.go new file mode 100644 index 00000000..e61b48cf --- /dev/null +++ b/apinetlet/controllers/network_peering_controller_test.go @@ -0,0 +1,469 @@ +// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package controllers + +import ( + apinetv1alpha1 "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1" + apinetletclient "github.com/ironcore-dev/ironcore-net/apinetlet/client" + "github.com/ironcore-dev/ironcore-net/apinetlet/provider" + 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) + apiNetNs := SetupNamespace(&k8sClient) + SetupTest(apiNetNs) + + 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", + }, + }, + }, + }, + } + 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("waiting for the corresponding APINet networks to be created") + apiNetNetwork1 := &apinetv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: apiNetNs.Name, + Name: string(network1.UID), + }, + } + Eventually(Get(apiNetNetwork1)).Should(Succeed()) + + apiNetNetwork2 := &apinetv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: apiNetNs.Name, + Name: string(network2.UID), + }, + } + Eventually(Get(apiNetNetwork2)).Should(Succeed()) + + apiNetNetwork3 := &apinetv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: apiNetNs.Name, + Name: string(network3.UID), + }, + } + Eventually(Get(apiNetNetwork3)).Should(Succeed()) + + By("inspecting the created apinet networks") + Expect(apiNetNetwork1.Labels).To(Equal( + apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network1), + )) + Expect(apiNetNetwork1.Spec.ID).NotTo(BeEmpty()) + + Expect(apiNetNetwork2.Labels).To(Equal( + apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network2), + )) + Expect(apiNetNetwork2.Spec.ID).NotTo(BeEmpty()) + + By("waiting for networks to reference each other") + Eventually(Object(network1)). + Should(SatisfyAll( + HaveField("Spec.ProviderID", Equal(provider.GetNetworkID( + apiNetNetwork1.Namespace, + apiNetNetwork1.Name, + apiNetNetwork1.Spec.ID, + apiNetNetwork1.UID, + ))), + 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, + }, networkingv1alpha1.NetworkPeeringStatus{ + Name: network1.Spec.Peerings[1].Name, + })), + )) + + Eventually(Object(network2)). + Should(SatisfyAll( + HaveField("Spec.ProviderID", Equal(provider.GetNetworkID( + apiNetNetwork2.Namespace, + apiNetNetwork2.Name, + apiNetNetwork2.Spec.ID, + apiNetNetwork2.UID, + ))), + 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, + })), + )) + + Eventually(Object(network3)). + Should(SatisfyAll( + HaveField("Spec.ProviderID", Equal(provider.GetNetworkID( + apiNetNetwork3.Namespace, + apiNetNetwork3.Name, + apiNetNetwork3.Spec.ID, + apiNetNetwork3.UID, + ))), + 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, + })), + )) + + By("ensuring apinet network peeredIDs are updated") + Eventually(Object(apiNetNetwork1)).Should(SatisfyAll( + HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork2.Spec.ID, apiNetNetwork3.Spec.ID)), + )) + + Eventually(Object(apiNetNetwork2)).Should(SatisfyAll( + HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork1.Spec.ID)), + )) + + Eventually(Object(apiNetNetwork2)).Should(SatisfyAll( + HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork1.Spec.ID)), + )) + + 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)) + + By("asserting the corresponding apinet network is gone as well") + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork1), apiNetNetwork1)).To(Satisfy(apierrors.IsNotFound)) + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork2), apiNetNetwork2)).To(Satisfy(apierrors.IsNotFound)) + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork3), apiNetNetwork3)).To(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("waiting for the corresponding APINet networks to be created") + apiNetNetwork1 := &apinetv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: apiNetNs.Name, + Name: string(network1.UID), + }, + } + Eventually(Get(apiNetNetwork1)).Should(Succeed()) + + apiNetNetwork2 := &apinetv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: apiNetNs.Name, + Name: string(network2.UID), + }, + } + Eventually(Get(apiNetNetwork2)).Should(Succeed()) + + By("inspecting the created apinet networks") + Expect(apiNetNetwork1.Labels).To(Equal( + apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network1), + )) + Expect(apiNetNetwork1.Spec.ID).NotTo(BeEmpty()) + + Expect(apiNetNetwork2.Labels).To(Equal( + apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network2), + )) + Expect(apiNetNetwork2.Spec.ID).NotTo(BeEmpty()) + + By("waiting for networks to reference each other") + Eventually(Object(network1)). + Should(SatisfyAll( + HaveField("Spec.ProviderID", Equal(provider.GetNetworkID( + apiNetNetwork1.Namespace, + apiNetNetwork1.Name, + apiNetNetwork1.Spec.ID, + apiNetNetwork1.UID, + ))), + 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, + })), + )) + + Eventually(Object(network2)). + Should(SatisfyAll( + HaveField("Spec.ProviderID", Equal(provider.GetNetworkID( + apiNetNetwork2.Namespace, + apiNetNetwork2.Name, + apiNetNetwork2.Spec.ID, + apiNetNetwork2.UID, + ))), + 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, + })), + )) + + By("ensuring apinet network peeredIDs are updated") + Eventually(Object(apiNetNetwork1)).Should(SatisfyAll( + HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork2.Spec.ID)), + )) + + Eventually(Object(apiNetNetwork2)).Should(SatisfyAll( + HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork1.Spec.ID)), + )) + + 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)) + + By("asserting the corresponding apinet network is gone as well") + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork1), apiNetNetwork1)).To(Satisfy(apierrors.IsNotFound)) + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork2), apiNetNetwork2)).To(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("waiting for the corresponding APINet networks to be created") + apiNetNetwork1 := &apinetv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: apiNetNs.Name, + Name: string(network1.UID), + }, + } + Eventually(Get(apiNetNetwork1)).Should(Succeed()) + + apiNetNetwork2 := &apinetv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: apiNetNs.Name, + Name: string(network2.UID), + }, + } + Eventually(Get(apiNetNetwork2)).Should(Succeed()) + + By("inspecting the created apinet networks") + Expect(apiNetNetwork1.Labels).To(Equal( + apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network1), + )) + Expect(apiNetNetwork1.Spec.ID).NotTo(BeEmpty()) + + Expect(apiNetNetwork2.Labels).To(Equal( + apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network2), + )) + Expect(apiNetNetwork2.Spec.ID).NotTo(BeEmpty()) + + By("ensuring both networks do not get peered") + Eventually(Object(network1)). + Should(SatisfyAll( + HaveField("Spec.ProviderID", Equal(provider.GetNetworkID( + apiNetNetwork1.Namespace, + apiNetNetwork1.Name, + apiNetNetwork1.Spec.ID, + apiNetNetwork1.UID, + ))), + HaveField("Spec.PeeringClaimRefs", BeEmpty()), + HaveField("Status.State", Equal(networkingv1alpha1.NetworkStateAvailable)), + HaveField("Status.Peerings", BeEmpty()), + )) + + Eventually(Object(network2)). + Should(SatisfyAll( + HaveField("Spec.ProviderID", Equal(provider.GetNetworkID( + apiNetNetwork2.Namespace, + apiNetNetwork2.Name, + apiNetNetwork2.Spec.ID, + apiNetNetwork2.UID, + ))), + HaveField("Spec.PeeringClaimRefs", BeEmpty()), + HaveField("Status.State", Equal(networkingv1alpha1.NetworkStateAvailable)), + HaveField("Status.Peerings", BeEmpty()), + )) + + By("ensuring apinet network peeredIDs are empty") + Eventually(Object(apiNetNetwork1)).Should(SatisfyAll( + HaveField("Spec.PeeredIDs", BeEmpty()), + )) + + Eventually(Object(apiNetNetwork2)).Should(SatisfyAll( + HaveField("Spec.PeeredIDs", BeEmpty()), + )) + + 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)) + + By("asserting the corresponding apinet network is gone as well") + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork1), apiNetNetwork1)).To(Satisfy(apierrors.IsNotFound)) + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork2), apiNetNetwork2)).To(Satisfy(apierrors.IsNotFound)) + }) +}) diff --git a/client-go/applyconfigurations/core/v1alpha1/networkspec.go b/client-go/applyconfigurations/core/v1alpha1/networkspec.go index 3af55c69..9b273a31 100644 --- a/client-go/applyconfigurations/core/v1alpha1/networkspec.go +++ b/client-go/applyconfigurations/core/v1alpha1/networkspec.go @@ -8,7 +8,8 @@ package v1alpha1 // NetworkSpecApplyConfiguration represents an declarative configuration of the NetworkSpec type for use // with apply. type NetworkSpecApplyConfiguration struct { - ID *string `json:"id,omitempty"` + ID *string `json:"id,omitempty"` + PeeredIDs []string `json:"peeredIDs,omitempty"` } // NetworkSpecApplyConfiguration constructs an declarative configuration of the NetworkSpec type for use with @@ -24,3 +25,13 @@ func (b *NetworkSpecApplyConfiguration) WithID(value string) *NetworkSpecApplyCo b.ID = &value return b } + +// WithPeeredIDs adds the given value to the PeeredIDs field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the PeeredIDs field. +func (b *NetworkSpecApplyConfiguration) WithPeeredIDs(values ...string) *NetworkSpecApplyConfiguration { + for i := range values { + b.PeeredIDs = append(b.PeeredIDs, values[i]) + } + return b +} diff --git a/client-go/applyconfigurations/internal/internal.go b/client-go/applyconfigurations/internal/internal.go index 5748facb..25097e07 100644 --- a/client-go/applyconfigurations/internal/internal.go +++ b/client-go/applyconfigurations/internal/internal.go @@ -772,6 +772,12 @@ var schemaYAML = typed.YAMLObject(`types: - name: id type: scalar: string + - name: peeredIDs + type: + list: + elementType: + scalar: string + elementRelationship: atomic - name: com.github.ironcore-dev.ironcore-net.api.core.v1alpha1.NetworkStatus map: elementType: diff --git a/client-go/openapi/api_violations.report b/client-go/openapi/api_violations.report index 125a08aa..f7127c59 100644 --- a/client-go/openapi/api_violations.report +++ b/client-go/openapi/api_violations.report @@ -16,6 +16,7 @@ API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/c API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/core/v1alpha1,NetworkInterfaceStatus,NATIPs API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/core/v1alpha1,NetworkInterfaceStatus,Prefixes API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/core/v1alpha1,NetworkInterfaceStatus,PublicIPs +API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/core/v1alpha1,NetworkSpec,PeeredIDs API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/core/v1alpha1,NodeSelector,NodeSelectorTerms API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/core/v1alpha1,NodeSelectorRequirement,Values API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/core/v1alpha1,NodeSelectorTerm,MatchExpressions diff --git a/client-go/openapi/zz_generated.openapi.go b/client-go/openapi/zz_generated.openapi.go index 2b07a468..f338a7cf 100644 --- a/client-go/openapi/zz_generated.openapi.go +++ b/client-go/openapi/zz_generated.openapi.go @@ -2778,6 +2778,21 @@ func schema_ironcore_net_api_core_v1alpha1_NetworkSpec(ref common.ReferenceCallb Format: "", }, }, + "peeredIDs": { + SchemaProps: spec.SchemaProps{ + Description: "PeeredIDs are the IDs of networks to peer with.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, }, }, }, diff --git a/cmd/apinetlet/main.go b/cmd/apinetlet/main.go index 4c96bf5b..028f8422 100644 --- a/cmd/apinetlet/main.go +++ b/cmd/apinetlet/main.go @@ -200,6 +200,16 @@ func main() { os.Exit(1) } + if err = (&controllers.NetworkPeeringReconciler{ + Client: mgr.GetClient(), + APINetClient: apiNetCluster.GetClient(), + APINetNamespace: apiNetNamespace, + WatchFilterValue: watchFilterValue, + }).SetupWithManager(mgr, apiNetCluster.GetCache()); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "NetworkPeering") + os.Exit(1) + } + if err = (&controllers.NetworkInterfaceReconciler{ Client: mgr.GetClient(), APINetClient: apiNetCluster.GetClient(), diff --git a/internal/apis/core/network_types.go b/internal/apis/core/network_types.go index 29de3567..743ccd8d 100644 --- a/internal/apis/core/network_types.go +++ b/internal/apis/core/network_types.go @@ -10,6 +10,8 @@ import ( type NetworkSpec struct { // ID is the ID of the network. ID string + // PeeredIDs are the IDs of networks to peer with. + PeeredIDs []string `json:"peeredIDs,omitempty"` } type NetworkStatus struct { diff --git a/internal/apis/core/v1alpha1/zz_generated.conversion.go b/internal/apis/core/v1alpha1/zz_generated.conversion.go index a59e854f..39042b19 100644 --- a/internal/apis/core/v1alpha1/zz_generated.conversion.go +++ b/internal/apis/core/v1alpha1/zz_generated.conversion.go @@ -2179,6 +2179,7 @@ func Convert_core_NetworkList_To_v1alpha1_NetworkList(in *core.NetworkList, out func autoConvert_v1alpha1_NetworkSpec_To_core_NetworkSpec(in *v1alpha1.NetworkSpec, out *core.NetworkSpec, s conversion.Scope) error { out.ID = in.ID + out.PeeredIDs = *(*[]string)(unsafe.Pointer(&in.PeeredIDs)) return nil } @@ -2189,6 +2190,7 @@ func Convert_v1alpha1_NetworkSpec_To_core_NetworkSpec(in *v1alpha1.NetworkSpec, func autoConvert_core_NetworkSpec_To_v1alpha1_NetworkSpec(in *core.NetworkSpec, out *v1alpha1.NetworkSpec, s conversion.Scope) error { out.ID = in.ID + out.PeeredIDs = *(*[]string)(unsafe.Pointer(&in.PeeredIDs)) return nil } diff --git a/internal/apis/core/zz_generated.deepcopy.go b/internal/apis/core/zz_generated.deepcopy.go index 9c40dbd1..13cd7b8a 100644 --- a/internal/apis/core/zz_generated.deepcopy.go +++ b/internal/apis/core/zz_generated.deepcopy.go @@ -1176,7 +1176,7 @@ func (in *Network) DeepCopyInto(out *Network) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec + in.Spec.DeepCopyInto(&out.Spec) out.Status = in.Status return } @@ -1525,6 +1525,11 @@ func (in *NetworkList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NetworkSpec) DeepCopyInto(out *NetworkSpec) { *out = *in + if in.PeeredIDs != nil { + in, out := &in.PeeredIDs, &out.PeeredIDs + *out = make([]string, len(*in)) + copy(*out, *in) + } return } From 4164342877162e30900df477025f80bb7c167e63 Mon Sep 17 00:00:00 2001 From: ushabelgur Date: Thu, 14 Mar 2024 14:54:49 +0530 Subject: [PATCH 2/9] implement network peering translation in metalnetlet --- metalnetlet/controllers/network_controller.go | 10 ++++++++++ metalnetlet/controllers/network_controller_test.go | 7 +++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/metalnetlet/controllers/network_controller.go b/metalnetlet/controllers/network_controller.go index 2d1d340e..986a90ed 100644 --- a/metalnetlet/controllers/network_controller.go +++ b/metalnetlet/controllers/network_controller.go @@ -144,6 +144,16 @@ func (r *NetworkReconciler) reconcile(ctx context.Context, log logr.Logger, netw ID: vni, }, } + + for _, peeredId := range network.Spec.PeeredIDs { + id, err := networkid.ParseVNI(peeredId) + if err != nil { + return ctrl.Result{}, fmt.Errorf("error converting network peering ID to int32: %w", err) + } + + metalnetNetwork.Spec.PeeredIDs = append(metalnetNetwork.Spec.PeeredIDs, int32(id)) + } + if err := r.MetalnetClient.Patch(ctx, metalnetNetwork, client.Apply, MetalnetFieldOwner, client.ForceOwnership); err != nil { return ctrl.Result{}, fmt.Errorf("error applying network: %w", err) } diff --git a/metalnetlet/controllers/network_controller_test.go b/metalnetlet/controllers/network_controller_test.go index baf8c24d..0e6e9105 100644 --- a/metalnetlet/controllers/network_controller_test.go +++ b/metalnetlet/controllers/network_controller_test.go @@ -26,7 +26,9 @@ var _ = Describe("NetworkController", func() { Namespace: ns.Name, GenerateName: "network-", }, - Spec: v1alpha1.NetworkSpec{}, + Spec: v1alpha1.NetworkSpec{ + PeeredIDs: []string{"123456", "234567"}, + }, } Expect(k8sClient.Create(ctx, network)).To(Succeed()) @@ -43,7 +45,8 @@ var _ = Describe("NetworkController", func() { } Eventually(Object(metalnetNetwork)).Should(SatisfyAll( HaveField("Spec", metalnetv1alpha1.NetworkSpec{ - ID: vni, + ID: vni, + PeeredIDs: []int32{123456, 234567}, }), )) }) From a8bc03b1ebb025fc08dddd1a96e1da573282a4d7 Mon Sep 17 00:00:00 2001 From: Kajol Asabe Date: Fri, 15 Mar 2024 13:50:23 +0530 Subject: [PATCH 3/9] change name of enque function --- apinetlet/controllers/network_peering_controller.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apinetlet/controllers/network_peering_controller.go b/apinetlet/controllers/network_peering_controller.go index 7a5906c4..d587c838 100644 --- a/apinetlet/controllers/network_peering_controller.go +++ b/apinetlet/controllers/network_peering_controller.go @@ -229,7 +229,7 @@ func (r *NetworkPeeringReconciler) reconcilePeering( return networkingv1alpha1.NetworkPeeringClaimRef{}, "", "", nil } -func (r *NetworkPeeringReconciler) enqueueNetworksHavingPeerings() handler.EventHandler { +func (r *NetworkPeeringReconciler) enqueueNetworksForPeering() handler.EventHandler { return handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []ctrl.Request { log := ctrl.LoggerFrom(ctx) networkList := &networkingv1alpha1.NetworkList{} @@ -263,7 +263,7 @@ func (r *NetworkPeeringReconciler) SetupWithManager(mgr ctrl.Manager, apiNetCach ). Watches( &networkingv1alpha1.Network{}, - r.enqueueNetworksHavingPeerings(), + r.enqueueNetworksForPeering(), builder.WithPredicates(r.networkStateAvailablePredicate()), ). Complete(r) From 26afee7ed2e42e51317de6f2a0be95aa6685e1c6 Mon Sep 17 00:00:00 2001 From: Kajol Asabe Date: Fri, 15 Mar 2024 15:48:00 +0530 Subject: [PATCH 4/9] address review comments --- .../controllers/network_peering_controller.go | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/apinetlet/controllers/network_peering_controller.go b/apinetlet/controllers/network_peering_controller.go index d587c838..1a84b3f8 100644 --- a/apinetlet/controllers/network_peering_controller.go +++ b/apinetlet/controllers/network_peering_controller.go @@ -10,9 +10,9 @@ import ( "github.com/go-logr/logr" apinetv1alpha1 "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1" networkingv1alpha1 "github.com/ironcore-dev/ironcore/api/networking/v1alpha1" - clientutils "github.com/ironcore-dev/ironcore/utils/client" "github.com/ironcore-dev/ironcore/utils/predicates" 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/cache" @@ -106,6 +106,8 @@ func (r *NetworkPeeringReconciler) updateStatus( for _, name := range peeringNames { newStatusPeerings = append(newStatusPeerings, networkingv1alpha1.NetworkPeeringStatus{ Name: name, + // TODO - Add other Peering Status fields when NetworkPeeringStatus + // is extended with Phase or any other status field in ironcore }) } network.Status.Peerings = newStatusPeerings @@ -181,10 +183,10 @@ func (r *NetworkPeeringReconciler) reconcilePeering( targetNetworkKey := client.ObjectKey{Namespace: targetNetworkNamespace, Name: targetNetworkRef.Name} log = log.WithValues("TargetNetworkKey", targetNetworkKey) - log.V(2).Info("Getting target network") + 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 network %s: %w", targetNetworkKey, err) + return networkingv1alpha1.NetworkPeeringClaimRef{}, "", "", fmt.Errorf("error getting target network %s: %w", targetNetworkKey, err) } log.V(1).Info("Target network not found") @@ -229,16 +231,21 @@ func (r *NetworkPeeringReconciler) reconcilePeering( return networkingv1alpha1.NetworkPeeringClaimRef{}, "", "", nil } -func (r *NetworkPeeringReconciler) enqueueNetworksForPeering() handler.EventHandler { +func (r *NetworkPeeringReconciler) enqueuePeeringReferencedNetworks() handler.EventHandler { return handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []ctrl.Request { - log := ctrl.LoggerFrom(ctx) - networkList := &networkingv1alpha1.NetworkList{} - if err := r.List(ctx, networkList); err != nil { - log.Error(err, "Error listing networks") - return nil + 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 clientutils.ReconcileRequestsFromObjectStructSlice[*networkingv1alpha1.Network](networkList.Items) + return reqs.UnsortedList() }) } @@ -263,7 +270,7 @@ func (r *NetworkPeeringReconciler) SetupWithManager(mgr ctrl.Manager, apiNetCach ). Watches( &networkingv1alpha1.Network{}, - r.enqueueNetworksForPeering(), + r.enqueuePeeringReferencedNetworks(), builder.WithPredicates(r.networkStateAvailablePredicate()), ). Complete(r) From c30b9770d17083f8099a58f88009a523f60d3a40 Mon Sep 17 00:00:00 2001 From: Kajol Asabe Date: Fri, 15 Mar 2024 16:17:48 +0530 Subject: [PATCH 5/9] Add network peering test for networks referencing each other --- .../network_peering_controller_test.go | 311 +++++++++++++++++- 1 file changed, 308 insertions(+), 3 deletions(-) diff --git a/apinetlet/controllers/network_peering_controller_test.go b/apinetlet/controllers/network_peering_controller_test.go index e61b48cf..fae14255 100644 --- a/apinetlet/controllers/network_peering_controller_test.go +++ b/apinetlet/controllers/network_peering_controller_test.go @@ -23,7 +23,7 @@ var _ = Describe("NetworkPeeringController", func() { apiNetNs := SetupNamespace(&k8sClient) SetupTest(apiNetNs) - It("should peer networks in the same namespace referencing each other", func(ctx SpecContext) { + 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{ @@ -45,6 +45,13 @@ var _ = Describe("NetworkPeeringController", func() { Name: "network-3", }, }, + { + Name: "peering-3", + NetworkRef: networkingv1alpha1.NetworkPeeringNetworkRef{ + Name: "network-4", + Namespace: ns.Name, + }, + }, }, }, } @@ -90,6 +97,26 @@ var _ = Describe("NetworkPeeringController", func() { } 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("waiting for the corresponding APINet networks to be created") apiNetNetwork1 := &apinetv1alpha1.Network{ ObjectMeta: metav1.ObjectMeta{ @@ -115,6 +142,14 @@ var _ = Describe("NetworkPeeringController", func() { } Eventually(Get(apiNetNetwork3)).Should(Succeed()) + apiNetNetwork4 := &apinetv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: apiNetNs.Name, + Name: string(network4.UID), + }, + } + Eventually(Get(apiNetNetwork4)).Should(Succeed()) + By("inspecting the created apinet networks") Expect(apiNetNetwork1.Labels).To(Equal( apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network1), @@ -126,6 +161,16 @@ var _ = Describe("NetworkPeeringController", func() { )) Expect(apiNetNetwork2.Spec.ID).NotTo(BeEmpty()) + Expect(apiNetNetwork3.Labels).To(Equal( + apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network3), + )) + Expect(apiNetNetwork3.Spec.ID).NotTo(BeEmpty()) + + Expect(apiNetNetwork4.Labels).To(Equal( + apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network4), + )) + Expect(apiNetNetwork4.Spec.ID).NotTo(BeEmpty()) + By("waiting for networks to reference each other") Eventually(Object(network1)). Should(SatisfyAll( @@ -143,12 +188,18 @@ var _ = Describe("NetworkPeeringController", func() { 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, }, networkingv1alpha1.NetworkPeeringStatus{ Name: network1.Spec.Peerings[1].Name, + }, networkingv1alpha1.NetworkPeeringStatus{ + Name: network1.Spec.Peerings[2].Name, })), )) @@ -190,16 +241,39 @@ var _ = Describe("NetworkPeeringController", func() { })), )) + Eventually(Object(network4)). + Should(SatisfyAll( + HaveField("Spec.ProviderID", Equal(provider.GetNetworkID( + apiNetNetwork4.Namespace, + apiNetNetwork4.Name, + apiNetNetwork4.Spec.ID, + apiNetNetwork4.UID, + ))), + 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, + })), + )) + By("ensuring apinet network peeredIDs are updated") Eventually(Object(apiNetNetwork1)).Should(SatisfyAll( - HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork2.Spec.ID, apiNetNetwork3.Spec.ID)), + HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork2.Spec.ID, apiNetNetwork3.Spec.ID, apiNetNetwork4.Spec.ID)), )) Eventually(Object(apiNetNetwork2)).Should(SatisfyAll( HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork1.Spec.ID)), )) - Eventually(Object(apiNetNetwork2)).Should(SatisfyAll( + Eventually(Object(apiNetNetwork3)).Should(SatisfyAll( + HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork1.Spec.ID)), + )) + + Eventually(Object(apiNetNetwork4)).Should(SatisfyAll( HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork1.Spec.ID)), )) @@ -207,16 +281,19 @@ var _ = Describe("NetworkPeeringController", func() { 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)) By("asserting the corresponding apinet network is gone as well") Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork1), apiNetNetwork1)).To(Satisfy(apierrors.IsNotFound)) Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork2), apiNetNetwork2)).To(Satisfy(apierrors.IsNotFound)) Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork3), apiNetNetwork3)).To(Satisfy(apierrors.IsNotFound)) + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork4), apiNetNetwork4)).To(Satisfy(apierrors.IsNotFound)) }) It("should peer two networks from different namespaces if they reference each other correctly", func(ctx SpecContext) { @@ -466,4 +543,232 @@ var _ = Describe("NetworkPeeringController", func() { Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork1), apiNetNetwork1)).To(Satisfy(apierrors.IsNotFound)) Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork2), apiNetNetwork2)).To(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("waiting for the corresponding APINet networks to be created") + apiNetNetwork1 := &apinetv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: apiNetNs.Name, + Name: string(network1.UID), + }, + } + Eventually(Get(apiNetNetwork1)).Should(Succeed()) + + apiNetNetwork2 := &apinetv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: apiNetNs.Name, + Name: string(network2.UID), + }, + } + Eventually(Get(apiNetNetwork2)).Should(Succeed()) + + apiNetNetwork3 := &apinetv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: apiNetNs.Name, + Name: string(network3.UID), + }, + } + Eventually(Get(apiNetNetwork3)).Should(Succeed()) + + By("inspecting the created apinet networks") + Expect(apiNetNetwork1.Labels).To(Equal( + apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network1), + )) + Expect(apiNetNetwork1.Spec.ID).NotTo(BeEmpty()) + + Expect(apiNetNetwork2.Labels).To(Equal( + apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network2), + )) + Expect(apiNetNetwork2.Spec.ID).NotTo(BeEmpty()) + + Expect(apiNetNetwork3.Labels).To(Equal( + apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network3), + )) + Expect(apiNetNetwork3.Spec.ID).NotTo(BeEmpty()) + + By("waiting for networks to reference each other") + Eventually(Object(network1)). + Should(SatisfyAll( + HaveField("Spec.ProviderID", Equal(provider.GetNetworkID( + apiNetNetwork1.Namespace, + apiNetNetwork1.Name, + apiNetNetwork1.Spec.ID, + apiNetNetwork1.UID, + ))), + 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, + }, networkingv1alpha1.NetworkPeeringStatus{ + Name: network1.Spec.Peerings[1].Name, + })), + )) + + Eventually(Object(network2)). + Should(SatisfyAll( + HaveField("Spec.ProviderID", Equal(provider.GetNetworkID( + apiNetNetwork2.Namespace, + apiNetNetwork2.Name, + apiNetNetwork2.Spec.ID, + apiNetNetwork2.UID, + ))), + 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, + }, networkingv1alpha1.NetworkPeeringStatus{ + Name: network2.Spec.Peerings[1].Name, + })), + )) + + Eventually(Object(network3)). + Should(SatisfyAll( + HaveField("Spec.ProviderID", Equal(provider.GetNetworkID( + apiNetNetwork3.Namespace, + apiNetNetwork3.Name, + apiNetNetwork3.Spec.ID, + apiNetNetwork3.UID, + ))), + 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, + }, networkingv1alpha1.NetworkPeeringStatus{ + Name: network3.Spec.Peerings[1].Name, + })), + )) + + By("ensuring apinet network peeredIDs are updated") + Eventually(Object(apiNetNetwork1)).Should(SatisfyAll( + HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork2.Spec.ID, apiNetNetwork3.Spec.ID)), + )) + + Eventually(Object(apiNetNetwork2)).Should(SatisfyAll( + HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork1.Spec.ID, apiNetNetwork3.Spec.ID)), + )) + + Eventually(Object(apiNetNetwork3)).Should(SatisfyAll( + HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork1.Spec.ID, apiNetNetwork2.Spec.ID)), + )) + + 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)) + + By("asserting the corresponding apinet network is gone as well") + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork1), apiNetNetwork1)).To(Satisfy(apierrors.IsNotFound)) + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork2), apiNetNetwork2)).To(Satisfy(apierrors.IsNotFound)) + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork3), apiNetNetwork3)).To(Satisfy(apierrors.IsNotFound)) + }) }) From 2312f4398cb5f7500ee814fc205d6658d325e9e7 Mon Sep 17 00:00:00 2001 From: Kajol Asabe Date: Tue, 26 Mar 2024 13:44:18 +0530 Subject: [PATCH 6/9] update network controller in apinetlet to handle peerings --- api/core/v1alpha1/network_types.go | 24 + api/core/v1alpha1/zz_generated.deepcopy.go | 23 +- .../controllers/controllers_suite_test.go | 6 - apinetlet/controllers/network_controller.go | 22 + .../controllers/network_controller_test.go | 123 ++- .../controllers/network_peering_controller.go | 277 ------- .../network_peering_controller_test.go | 774 ------------------ .../core/v1alpha1/network.go | 8 +- .../core/v1alpha1/networkpeeringstatus.go | 39 + .../core/v1alpha1/networkstatus.go | 31 + .../applyconfigurations/internal/internal.go | 27 +- client-go/applyconfigurations/utils.go | 4 + client-go/openapi/api_violations.report | 1 + client-go/openapi/zz_generated.openapi.go | 48 ++ cmd/apinetlet/main.go | 10 - docs/concepts/network-lifecycle.md | 11 +- internal/apis/core/network_types.go | 26 +- .../core/v1alpha1/zz_generated.conversion.go | 34 + internal/apis/core/zz_generated.deepcopy.go | 23 +- 19 files changed, 417 insertions(+), 1094 deletions(-) delete mode 100644 apinetlet/controllers/network_peering_controller.go delete mode 100644 apinetlet/controllers/network_peering_controller_test.go create mode 100644 client-go/applyconfigurations/core/v1alpha1/networkpeeringstatus.go create mode 100644 client-go/applyconfigurations/core/v1alpha1/networkstatus.go diff --git a/api/core/v1alpha1/network_types.go b/api/core/v1alpha1/network_types.go index 0259a646..dca5ad68 100644 --- a/api/core/v1alpha1/network_types.go +++ b/api/core/v1alpha1/network_types.go @@ -15,6 +15,30 @@ type NetworkSpec struct { } type NetworkStatus struct { + // Peerings contains the states of the network peerings for the network. + Peerings []NetworkPeeringStatus `json:"peerings,omitempty"` +} + +// NetworkState is the state of a network. +// +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"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/api/core/v1alpha1/zz_generated.deepcopy.go b/api/core/v1alpha1/zz_generated.deepcopy.go index ecd83c4e..6aaf104e 100644 --- a/api/core/v1alpha1/zz_generated.deepcopy.go +++ b/api/core/v1alpha1/zz_generated.deepcopy.go @@ -1177,7 +1177,7 @@ func (in *Network) DeepCopyInto(out *Network) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - out.Status = in.Status + in.Status.DeepCopyInto(&out.Status) return } @@ -1522,6 +1522,22 @@ func (in *NetworkList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkPeeringStatus) DeepCopyInto(out *NetworkPeeringStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkPeeringStatus. +func (in *NetworkPeeringStatus) DeepCopy() *NetworkPeeringStatus { + if in == nil { + return nil + } + out := new(NetworkPeeringStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NetworkSpec) DeepCopyInto(out *NetworkSpec) { *out = *in @@ -1546,6 +1562,11 @@ func (in *NetworkSpec) DeepCopy() *NetworkSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NetworkStatus) DeepCopyInto(out *NetworkStatus) { *out = *in + if in.Peerings != nil { + in, out := &in.Peerings, &out.Peerings + *out = make([]NetworkPeeringStatus, len(*in)) + copy(*out, *in) + } return } diff --git a/apinetlet/controllers/controllers_suite_test.go b/apinetlet/controllers/controllers_suite_test.go index ad0a3c0d..8f9f13a6 100644 --- a/apinetlet/controllers/controllers_suite_test.go +++ b/apinetlet/controllers/controllers_suite_test.go @@ -154,12 +154,6 @@ func SetupTest(apiNetNamespace *corev1.Namespace) *corev1.Namespace { APINetNamespace: apiNetNamespace.Name, }).SetupWithManager(k8sManager, k8sManager.GetCache())).To(Succeed()) - Expect((&NetworkPeeringReconciler{ - Client: k8sManager.GetClient(), - APINetClient: k8sManager.GetClient(), - APINetNamespace: apiNetNamespace.Name, - }).SetupWithManager(k8sManager, k8sManager.GetCache())).To(Succeed()) - Expect((&NetworkInterfaceReconciler{ Client: k8sManager.GetClient(), APINetClient: k8sManager.GetClient(), diff --git a/apinetlet/controllers/network_controller.go b/apinetlet/controllers/network_controller.go index 06914801..26cbbcf4 100644 --- a/apinetlet/controllers/network_controller.go +++ b/apinetlet/controllers/network_controller.go @@ -193,6 +193,28 @@ func (r *NetworkReconciler) applyAPINetNetwork(ctx context.Context, log logr.Log }, } + var peeredIDs []string + for _, peeringClaimRef := range network.Spec.PeeringClaimRefs { + log.V(1).Info("Get apinet network for target network") + targetApinetNetwork := &apinetv1alpha1.Network{} + if err := r.APINetClient.Get(ctx, client.ObjectKey{Namespace: r.APINetNamespace, Name: string(peeringClaimRef.UID)}, targetApinetNetwork); err != nil { + log.V(1).Info("target apinet network is not created yet") + break + } + peeredIDs = append(peeredIDs, targetApinetNetwork.Spec.ID) + } + apiNetNetwork.Spec.PeeredIDs = peeredIDs + + var peerings []apinetv1alpha1.NetworkPeeringStatus + for _, peering := range network.Status.Peerings { + peerings = append(peerings, apinetv1alpha1.NetworkPeeringStatus{ + Name: peering.Name, + // TODO remove below comment after merging ironcore PR #1026 + // State: peering.State, + }) + } + apiNetNetwork.Status.Peerings = peerings + log.V(1).Info("Applying APINet network") if err := r.APINetClient.Patch(ctx, apiNetNetwork, client.Apply, fieldOwner, client.ForceOwnership); err != nil { return nil, fmt.Errorf("error applying apinet network: %w", err) diff --git a/apinetlet/controllers/network_controller_test.go b/apinetlet/controllers/network_controller_test.go index a2cfba6d..4b34349b 100644 --- a/apinetlet/controllers/network_controller_test.go +++ b/apinetlet/controllers/network_controller_test.go @@ -4,7 +4,7 @@ package controllers import ( - "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1" + apinetv1alpha1 "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1" apinetletclient "github.com/ironcore-dev/ironcore-net/apinetlet/client" "github.com/ironcore-dev/ironcore-net/apinetlet/provider" networkingv1alpha1 "github.com/ironcore-dev/ironcore/api/networking/v1alpha1" @@ -19,6 +19,7 @@ import ( var _ = Describe("NetworkController", func() { ns := SetupNamespace(&k8sClient) + ns1 := SetupNamespace(&k8sClient) apiNetNs := SetupNamespace(&k8sClient) SetupTest(apiNetNs) @@ -33,7 +34,7 @@ var _ = Describe("NetworkController", func() { Expect(k8sClient.Create(ctx, network)).To(Succeed()) By("waiting for the corresponding APINet network to be created") - apiNetNetwork := &v1alpha1.Network{ + apiNetNetwork := &apinetv1alpha1.Network{ ObjectMeta: metav1.ObjectMeta{ Namespace: apiNetNs.Name, Name: string(network.UID), @@ -71,7 +72,7 @@ var _ = Describe("NetworkController", func() { It("should clean up dangling apinet networks", func(ctx SpecContext) { By("creating a apinet network") - apiNetNetwork := &v1alpha1.Network{ + apiNetNetwork := &apinetv1alpha1.Network{ ObjectMeta: metav1.ObjectMeta{ Namespace: apiNetNs.Name, GenerateName: "apinet-network-", @@ -85,11 +86,125 @@ var _ = Describe("NetworkController", func() { }, ), }, - Spec: v1alpha1.NetworkSpec{}, + Spec: apinetv1alpha1.NetworkSpec{}, } Expect(k8sClient.Create(ctx, apiNetNetwork)).To(Succeed()) By("waiting for the apinet network to be gone") Eventually(Get(apiNetNetwork)).Should(Satisfy(apierrors.IsNotFound)) }) + + It("should update peeredIDs if two networks from different namespaces peers 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("waiting for the corresponding APINet networks to be created") + apiNetNetwork1 := &apinetv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: apiNetNs.Name, + Name: string(network1.UID), + }, + } + Eventually(Get(apiNetNetwork1)).Should(Succeed()) + + apiNetNetwork2 := &apinetv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: apiNetNs.Name, + Name: string(network2.UID), + }, + } + Eventually(Get(apiNetNetwork2)).Should(Succeed()) + + By("inspecting the created apinet networks") + Expect(apiNetNetwork1.Labels).To(Equal(apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network1))) + Expect(apiNetNetwork1.Spec.ID).NotTo(BeEmpty()) + + Expect(apiNetNetwork2.Labels).To(Equal(apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network2))) + Expect(apiNetNetwork2.Spec.ID).NotTo(BeEmpty()) + + By("patching networks with peeringClaimRefs") + baseNetwork1 := network1.DeepCopy() + network1.Spec.PeeringClaimRefs = []networkingv1alpha1.NetworkPeeringClaimRef{{ + Name: network2.Name, + Namespace: network2.Namespace, + UID: network2.UID, + }} + network1.Status.Peerings = []networkingv1alpha1.NetworkPeeringStatus{{ + Name: network1.Spec.Peerings[0].Name, + // TODO remove below comment after merging ironcore PR #1026 + // State: networkingv1alpha1.NetworkPeeringStatePending, + }} + Expect(k8sClient.Patch(ctx, network1, client.MergeFrom(baseNetwork1))).To(Succeed()) + + baseNetwork2 := network2.DeepCopy() + network2.Spec.PeeringClaimRefs = []networkingv1alpha1.NetworkPeeringClaimRef{{ + Name: network1.Name, + Namespace: network1.Namespace, + UID: network1.UID, + }} + network2.Status.Peerings = []networkingv1alpha1.NetworkPeeringStatus{{ + Name: network2.Spec.Peerings[0].Name, + // TODO remove below comment after merging ironcore PR #1026 + // State: networkingv1alpha1.NetworkPeeringStatePending, + }} + Expect(k8sClient.Patch(ctx, network2, client.MergeFrom(baseNetwork2))).To(Succeed()) + + By("ensuring apinet network peeredIDs are updated") + Eventually(Object(apiNetNetwork1)).Should(SatisfyAll( + HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork2.Spec.ID)), + )) + + Eventually(Object(apiNetNetwork2)).Should(SatisfyAll( + HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork1.Spec.ID)), + )) + + 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)) + + By("asserting the corresponding apinet network is gone as well") + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork1), apiNetNetwork1)).To(Satisfy(apierrors.IsNotFound)) + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork2), apiNetNetwork2)).To(Satisfy(apierrors.IsNotFound)) + }) }) diff --git a/apinetlet/controllers/network_peering_controller.go b/apinetlet/controllers/network_peering_controller.go deleted file mode 100644 index 1a84b3f8..00000000 --- a/apinetlet/controllers/network_peering_controller.go +++ /dev/null @@ -1,277 +0,0 @@ -// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and IronCore contributors -// SPDX-License-Identifier: Apache-2.0 - -package controllers - -import ( - "context" - "fmt" - - "github.com/go-logr/logr" - apinetv1alpha1 "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1" - networkingv1alpha1 "github.com/ironcore-dev/ironcore/api/networking/v1alpha1" - "github.com/ironcore-dev/ironcore/utils/predicates" - 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/cache" - "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 - APINetClient client.Client - APINetNamespace string - WatchFilterValue string -} - -//+kubebuilder:rbac:groups="",resources=events,verbs=create;patch -//+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 - -//+cluster=apinet:kubebuilder:rbac:groups=core.apinet.ironcore.dev,resources=networks,verbs=get;list;watch;create;update;patch;delete;deletecollection - -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 - var peeredIDs []string - - for _, peering := range network.Spec.Peerings { - peeringClaimRef, peeringName, peeredID, 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 peeringName != "" { - peeringNames = append(peeringNames, peeringName) - } - if peeredID != "" { - peeredIDs = append(peeredIDs, peeredID) - } - } - - if len(peeringClaimRefs) > 0 { - log.V(1).Info("Peering claim refs require network spec update") - if err := r.updateSpec(ctx, log, network, peeringClaimRefs, peeredIDs); 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, - // TODO - Add other Peering Status fields when NetworkPeeringStatus - // is extended with Phase or any other status field in ironcore - }) - } - 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, - peeredIDs []string, -) error { - if err := r.updateApinetNetworkSpec(ctx, log, network, peeredIDs); err != nil { - return fmt.Errorf("error updating apinet network spec: %w", err) - } - - 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) updateApinetNetworkSpec( - ctx context.Context, - log logr.Logger, - network *networkingv1alpha1.Network, - peeredIDs []string, -) error { - apinetNetwork := &apinetv1alpha1.Network{} - apinetNetworkKey := client.ObjectKey{Namespace: r.APINetNamespace, Name: string(network.UID)} - if err := r.APINetClient.Get(ctx, apinetNetworkKey, apinetNetwork); err != nil { - return fmt.Errorf("apinet network is not created yet for network: %s \n %w", network.Name, err) - } - - base := apinetNetwork.DeepCopy() - apinetNetwork.Spec.PeeredIDs = peeredIDs - log.V(1).Info("Updating apinet network spec peered ids") - if err := r.APINetClient.Patch(ctx, apinetNetwork, client.StrategicMergeFrom(base)); err != nil { - return fmt.Errorf("error updating apinet network spec peered ids: %w", err) - } - - log.V(1).Info("Updated apinet network spec peered ids") - return nil -} - -func (r *NetworkPeeringReconciler) reconcilePeering( - ctx context.Context, - log logr.Logger, - network *networkingv1alpha1.Network, - peering networkingv1alpha1.NetworkPeering, -) (networkingv1alpha1.NetworkPeeringClaimRef, string, string, 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, - } - - log.V(1).Info("Get apinet network for target network") - apinetNetwork := &apinetv1alpha1.Network{} - if err := r.APINetClient.Get(ctx, client.ObjectKey{Namespace: r.APINetNamespace, Name: string(targetNetwork.UID)}, - apinetNetwork); err != nil { - log.V(1).Info("apinet network for target network is not created yet") - return networkingv1alpha1.NetworkPeeringClaimRef{}, "", "", nil - } - return peeringClaimRef, peering.Name, apinetNetwork.Spec.ID, 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, apiNetCache cache.Cache) error { - log := ctrl.Log.WithName("networkpeering").WithName("setup") - - return ctrl.NewControllerManagedBy(mgr). - For( - &networkingv1alpha1.Network{}, - builder.WithPredicates( - predicates.ResourceHasFilterLabel(log, r.WatchFilterValue), - predicates.ResourceIsNotExternallyManaged(log), - r.networkStateAvailablePredicate(), - ), - ). - Watches( - &networkingv1alpha1.Network{}, - r.enqueuePeeringReferencedNetworks(), - builder.WithPredicates(r.networkStateAvailablePredicate()), - ). - Complete(r) -} diff --git a/apinetlet/controllers/network_peering_controller_test.go b/apinetlet/controllers/network_peering_controller_test.go deleted file mode 100644 index fae14255..00000000 --- a/apinetlet/controllers/network_peering_controller_test.go +++ /dev/null @@ -1,774 +0,0 @@ -// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and IronCore contributors -// SPDX-License-Identifier: Apache-2.0 - -package controllers - -import ( - apinetv1alpha1 "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1" - apinetletclient "github.com/ironcore-dev/ironcore-net/apinetlet/client" - "github.com/ironcore-dev/ironcore-net/apinetlet/provider" - 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) - apiNetNs := SetupNamespace(&k8sClient) - SetupTest(apiNetNs) - - 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("waiting for the corresponding APINet networks to be created") - apiNetNetwork1 := &apinetv1alpha1.Network{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: apiNetNs.Name, - Name: string(network1.UID), - }, - } - Eventually(Get(apiNetNetwork1)).Should(Succeed()) - - apiNetNetwork2 := &apinetv1alpha1.Network{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: apiNetNs.Name, - Name: string(network2.UID), - }, - } - Eventually(Get(apiNetNetwork2)).Should(Succeed()) - - apiNetNetwork3 := &apinetv1alpha1.Network{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: apiNetNs.Name, - Name: string(network3.UID), - }, - } - Eventually(Get(apiNetNetwork3)).Should(Succeed()) - - apiNetNetwork4 := &apinetv1alpha1.Network{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: apiNetNs.Name, - Name: string(network4.UID), - }, - } - Eventually(Get(apiNetNetwork4)).Should(Succeed()) - - By("inspecting the created apinet networks") - Expect(apiNetNetwork1.Labels).To(Equal( - apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network1), - )) - Expect(apiNetNetwork1.Spec.ID).NotTo(BeEmpty()) - - Expect(apiNetNetwork2.Labels).To(Equal( - apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network2), - )) - Expect(apiNetNetwork2.Spec.ID).NotTo(BeEmpty()) - - Expect(apiNetNetwork3.Labels).To(Equal( - apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network3), - )) - Expect(apiNetNetwork3.Spec.ID).NotTo(BeEmpty()) - - Expect(apiNetNetwork4.Labels).To(Equal( - apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network4), - )) - Expect(apiNetNetwork4.Spec.ID).NotTo(BeEmpty()) - - By("waiting for networks to reference each other") - Eventually(Object(network1)). - Should(SatisfyAll( - HaveField("Spec.ProviderID", Equal(provider.GetNetworkID( - apiNetNetwork1.Namespace, - apiNetNetwork1.Name, - apiNetNetwork1.Spec.ID, - apiNetNetwork1.UID, - ))), - 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, - }, networkingv1alpha1.NetworkPeeringStatus{ - Name: network1.Spec.Peerings[1].Name, - }, networkingv1alpha1.NetworkPeeringStatus{ - Name: network1.Spec.Peerings[2].Name, - })), - )) - - Eventually(Object(network2)). - Should(SatisfyAll( - HaveField("Spec.ProviderID", Equal(provider.GetNetworkID( - apiNetNetwork2.Namespace, - apiNetNetwork2.Name, - apiNetNetwork2.Spec.ID, - apiNetNetwork2.UID, - ))), - 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, - })), - )) - - Eventually(Object(network3)). - Should(SatisfyAll( - HaveField("Spec.ProviderID", Equal(provider.GetNetworkID( - apiNetNetwork3.Namespace, - apiNetNetwork3.Name, - apiNetNetwork3.Spec.ID, - apiNetNetwork3.UID, - ))), - 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, - })), - )) - - Eventually(Object(network4)). - Should(SatisfyAll( - HaveField("Spec.ProviderID", Equal(provider.GetNetworkID( - apiNetNetwork4.Namespace, - apiNetNetwork4.Name, - apiNetNetwork4.Spec.ID, - apiNetNetwork4.UID, - ))), - 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, - })), - )) - - By("ensuring apinet network peeredIDs are updated") - Eventually(Object(apiNetNetwork1)).Should(SatisfyAll( - HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork2.Spec.ID, apiNetNetwork3.Spec.ID, apiNetNetwork4.Spec.ID)), - )) - - Eventually(Object(apiNetNetwork2)).Should(SatisfyAll( - HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork1.Spec.ID)), - )) - - Eventually(Object(apiNetNetwork3)).Should(SatisfyAll( - HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork1.Spec.ID)), - )) - - Eventually(Object(apiNetNetwork4)).Should(SatisfyAll( - HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork1.Spec.ID)), - )) - - 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)) - - By("asserting the corresponding apinet network is gone as well") - Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork1), apiNetNetwork1)).To(Satisfy(apierrors.IsNotFound)) - Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork2), apiNetNetwork2)).To(Satisfy(apierrors.IsNotFound)) - Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork3), apiNetNetwork3)).To(Satisfy(apierrors.IsNotFound)) - Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork4), apiNetNetwork4)).To(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("waiting for the corresponding APINet networks to be created") - apiNetNetwork1 := &apinetv1alpha1.Network{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: apiNetNs.Name, - Name: string(network1.UID), - }, - } - Eventually(Get(apiNetNetwork1)).Should(Succeed()) - - apiNetNetwork2 := &apinetv1alpha1.Network{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: apiNetNs.Name, - Name: string(network2.UID), - }, - } - Eventually(Get(apiNetNetwork2)).Should(Succeed()) - - By("inspecting the created apinet networks") - Expect(apiNetNetwork1.Labels).To(Equal( - apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network1), - )) - Expect(apiNetNetwork1.Spec.ID).NotTo(BeEmpty()) - - Expect(apiNetNetwork2.Labels).To(Equal( - apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network2), - )) - Expect(apiNetNetwork2.Spec.ID).NotTo(BeEmpty()) - - By("waiting for networks to reference each other") - Eventually(Object(network1)). - Should(SatisfyAll( - HaveField("Spec.ProviderID", Equal(provider.GetNetworkID( - apiNetNetwork1.Namespace, - apiNetNetwork1.Name, - apiNetNetwork1.Spec.ID, - apiNetNetwork1.UID, - ))), - 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, - })), - )) - - Eventually(Object(network2)). - Should(SatisfyAll( - HaveField("Spec.ProviderID", Equal(provider.GetNetworkID( - apiNetNetwork2.Namespace, - apiNetNetwork2.Name, - apiNetNetwork2.Spec.ID, - apiNetNetwork2.UID, - ))), - 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, - })), - )) - - By("ensuring apinet network peeredIDs are updated") - Eventually(Object(apiNetNetwork1)).Should(SatisfyAll( - HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork2.Spec.ID)), - )) - - Eventually(Object(apiNetNetwork2)).Should(SatisfyAll( - HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork1.Spec.ID)), - )) - - 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)) - - By("asserting the corresponding apinet network is gone as well") - Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork1), apiNetNetwork1)).To(Satisfy(apierrors.IsNotFound)) - Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork2), apiNetNetwork2)).To(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("waiting for the corresponding APINet networks to be created") - apiNetNetwork1 := &apinetv1alpha1.Network{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: apiNetNs.Name, - Name: string(network1.UID), - }, - } - Eventually(Get(apiNetNetwork1)).Should(Succeed()) - - apiNetNetwork2 := &apinetv1alpha1.Network{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: apiNetNs.Name, - Name: string(network2.UID), - }, - } - Eventually(Get(apiNetNetwork2)).Should(Succeed()) - - By("inspecting the created apinet networks") - Expect(apiNetNetwork1.Labels).To(Equal( - apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network1), - )) - Expect(apiNetNetwork1.Spec.ID).NotTo(BeEmpty()) - - Expect(apiNetNetwork2.Labels).To(Equal( - apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network2), - )) - Expect(apiNetNetwork2.Spec.ID).NotTo(BeEmpty()) - - By("ensuring both networks do not get peered") - Eventually(Object(network1)). - Should(SatisfyAll( - HaveField("Spec.ProviderID", Equal(provider.GetNetworkID( - apiNetNetwork1.Namespace, - apiNetNetwork1.Name, - apiNetNetwork1.Spec.ID, - apiNetNetwork1.UID, - ))), - HaveField("Spec.PeeringClaimRefs", BeEmpty()), - HaveField("Status.State", Equal(networkingv1alpha1.NetworkStateAvailable)), - HaveField("Status.Peerings", BeEmpty()), - )) - - Eventually(Object(network2)). - Should(SatisfyAll( - HaveField("Spec.ProviderID", Equal(provider.GetNetworkID( - apiNetNetwork2.Namespace, - apiNetNetwork2.Name, - apiNetNetwork2.Spec.ID, - apiNetNetwork2.UID, - ))), - HaveField("Spec.PeeringClaimRefs", BeEmpty()), - HaveField("Status.State", Equal(networkingv1alpha1.NetworkStateAvailable)), - HaveField("Status.Peerings", BeEmpty()), - )) - - By("ensuring apinet network peeredIDs are empty") - Eventually(Object(apiNetNetwork1)).Should(SatisfyAll( - HaveField("Spec.PeeredIDs", BeEmpty()), - )) - - Eventually(Object(apiNetNetwork2)).Should(SatisfyAll( - HaveField("Spec.PeeredIDs", BeEmpty()), - )) - - 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)) - - By("asserting the corresponding apinet network is gone as well") - Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork1), apiNetNetwork1)).To(Satisfy(apierrors.IsNotFound)) - Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork2), apiNetNetwork2)).To(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("waiting for the corresponding APINet networks to be created") - apiNetNetwork1 := &apinetv1alpha1.Network{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: apiNetNs.Name, - Name: string(network1.UID), - }, - } - Eventually(Get(apiNetNetwork1)).Should(Succeed()) - - apiNetNetwork2 := &apinetv1alpha1.Network{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: apiNetNs.Name, - Name: string(network2.UID), - }, - } - Eventually(Get(apiNetNetwork2)).Should(Succeed()) - - apiNetNetwork3 := &apinetv1alpha1.Network{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: apiNetNs.Name, - Name: string(network3.UID), - }, - } - Eventually(Get(apiNetNetwork3)).Should(Succeed()) - - By("inspecting the created apinet networks") - Expect(apiNetNetwork1.Labels).To(Equal( - apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network1), - )) - Expect(apiNetNetwork1.Spec.ID).NotTo(BeEmpty()) - - Expect(apiNetNetwork2.Labels).To(Equal( - apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network2), - )) - Expect(apiNetNetwork2.Spec.ID).NotTo(BeEmpty()) - - Expect(apiNetNetwork3.Labels).To(Equal( - apinetletclient.SourceLabels(k8sClient.Scheme(), k8sClient.RESTMapper(), network3), - )) - Expect(apiNetNetwork3.Spec.ID).NotTo(BeEmpty()) - - By("waiting for networks to reference each other") - Eventually(Object(network1)). - Should(SatisfyAll( - HaveField("Spec.ProviderID", Equal(provider.GetNetworkID( - apiNetNetwork1.Namespace, - apiNetNetwork1.Name, - apiNetNetwork1.Spec.ID, - apiNetNetwork1.UID, - ))), - 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, - }, networkingv1alpha1.NetworkPeeringStatus{ - Name: network1.Spec.Peerings[1].Name, - })), - )) - - Eventually(Object(network2)). - Should(SatisfyAll( - HaveField("Spec.ProviderID", Equal(provider.GetNetworkID( - apiNetNetwork2.Namespace, - apiNetNetwork2.Name, - apiNetNetwork2.Spec.ID, - apiNetNetwork2.UID, - ))), - 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, - }, networkingv1alpha1.NetworkPeeringStatus{ - Name: network2.Spec.Peerings[1].Name, - })), - )) - - Eventually(Object(network3)). - Should(SatisfyAll( - HaveField("Spec.ProviderID", Equal(provider.GetNetworkID( - apiNetNetwork3.Namespace, - apiNetNetwork3.Name, - apiNetNetwork3.Spec.ID, - apiNetNetwork3.UID, - ))), - 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, - }, networkingv1alpha1.NetworkPeeringStatus{ - Name: network3.Spec.Peerings[1].Name, - })), - )) - - By("ensuring apinet network peeredIDs are updated") - Eventually(Object(apiNetNetwork1)).Should(SatisfyAll( - HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork2.Spec.ID, apiNetNetwork3.Spec.ID)), - )) - - Eventually(Object(apiNetNetwork2)).Should(SatisfyAll( - HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork1.Spec.ID, apiNetNetwork3.Spec.ID)), - )) - - Eventually(Object(apiNetNetwork3)).Should(SatisfyAll( - HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork1.Spec.ID, apiNetNetwork2.Spec.ID)), - )) - - 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)) - - By("asserting the corresponding apinet network is gone as well") - Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork1), apiNetNetwork1)).To(Satisfy(apierrors.IsNotFound)) - Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork2), apiNetNetwork2)).To(Satisfy(apierrors.IsNotFound)) - Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(apiNetNetwork3), apiNetNetwork3)).To(Satisfy(apierrors.IsNotFound)) - }) -}) diff --git a/client-go/applyconfigurations/core/v1alpha1/network.go b/client-go/applyconfigurations/core/v1alpha1/network.go index 4e52ec3c..154b6383 100644 --- a/client-go/applyconfigurations/core/v1alpha1/network.go +++ b/client-go/applyconfigurations/core/v1alpha1/network.go @@ -19,8 +19,8 @@ import ( type NetworkApplyConfiguration struct { v1.TypeMetaApplyConfiguration `json:",inline"` *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` - Spec *NetworkSpecApplyConfiguration `json:"spec,omitempty"` - Status *corev1alpha1.NetworkStatus `json:"status,omitempty"` + Spec *NetworkSpecApplyConfiguration `json:"spec,omitempty"` + Status *NetworkStatusApplyConfiguration `json:"status,omitempty"` } // Network constructs an declarative configuration of the Network type for use with @@ -239,7 +239,7 @@ func (b *NetworkApplyConfiguration) WithSpec(value *NetworkSpecApplyConfiguratio // WithStatus sets the Status 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 Status field is set to the value of the last call. -func (b *NetworkApplyConfiguration) WithStatus(value corev1alpha1.NetworkStatus) *NetworkApplyConfiguration { - b.Status = &value +func (b *NetworkApplyConfiguration) WithStatus(value *NetworkStatusApplyConfiguration) *NetworkApplyConfiguration { + b.Status = value return b } diff --git a/client-go/applyconfigurations/core/v1alpha1/networkpeeringstatus.go b/client-go/applyconfigurations/core/v1alpha1/networkpeeringstatus.go new file mode 100644 index 00000000..5e392a4a --- /dev/null +++ b/client-go/applyconfigurations/core/v1alpha1/networkpeeringstatus.go @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1" +) + +// NetworkPeeringStatusApplyConfiguration represents an declarative configuration of the NetworkPeeringStatus type for use +// with apply. +type NetworkPeeringStatusApplyConfiguration struct { + Name *string `json:"name,omitempty"` + State *v1alpha1.NetworkPeeringState `json:"state,omitempty"` +} + +// NetworkPeeringStatusApplyConfiguration constructs an declarative configuration of the NetworkPeeringStatus type for use with +// apply. +func NetworkPeeringStatus() *NetworkPeeringStatusApplyConfiguration { + return &NetworkPeeringStatusApplyConfiguration{} +} + +// WithName sets the Name 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 Name field is set to the value of the last call. +func (b *NetworkPeeringStatusApplyConfiguration) WithName(value string) *NetworkPeeringStatusApplyConfiguration { + 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/applyconfigurations/core/v1alpha1/networkstatus.go b/client-go/applyconfigurations/core/v1alpha1/networkstatus.go new file mode 100644 index 00000000..02623207 --- /dev/null +++ b/client-go/applyconfigurations/core/v1alpha1/networkstatus.go @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// NetworkStatusApplyConfiguration represents an declarative configuration of the NetworkStatus type for use +// with apply. +type NetworkStatusApplyConfiguration struct { + Peerings []NetworkPeeringStatusApplyConfiguration `json:"peerings,omitempty"` +} + +// NetworkStatusApplyConfiguration constructs an declarative configuration of the NetworkStatus type for use with +// apply. +func NetworkStatus() *NetworkStatusApplyConfiguration { + return &NetworkStatusApplyConfiguration{} +} + +// WithPeerings adds the given value to the Peerings field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Peerings field. +func (b *NetworkStatusApplyConfiguration) WithPeerings(values ...*NetworkPeeringStatusApplyConfiguration) *NetworkStatusApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithPeerings") + } + b.Peerings = append(b.Peerings, *values[i]) + } + return b +} diff --git a/client-go/applyconfigurations/internal/internal.go b/client-go/applyconfigurations/internal/internal.go index 25097e07..cd18f237 100644 --- a/client-go/applyconfigurations/internal/internal.go +++ b/client-go/applyconfigurations/internal/internal.go @@ -766,6 +766,16 @@ var schemaYAML = typed.YAMLObject(`types: - name: state type: scalar: string +- name: com.github.ironcore-dev.ironcore-net.api.core.v1alpha1.NetworkPeeringStatus + map: + fields: + - name: name + type: + scalar: string + default: "" + - name: state + type: + scalar: string - name: com.github.ironcore-dev.ironcore-net.api.core.v1alpha1.NetworkSpec map: fields: @@ -780,16 +790,13 @@ var schemaYAML = typed.YAMLObject(`types: elementRelationship: atomic - name: com.github.ironcore-dev.ironcore-net.api.core.v1alpha1.NetworkStatus map: - elementType: - scalar: untyped - list: - elementType: - namedType: __untyped_atomic_ - elementRelationship: atomic - map: - elementType: - namedType: __untyped_deduced_ - elementRelationship: separable + fields: + - name: peerings + type: + list: + elementType: + namedType: com.github.ironcore-dev.ironcore-net.api.core.v1alpha1.NetworkPeeringStatus + elementRelationship: atomic - name: com.github.ironcore-dev.ironcore-net.api.core.v1alpha1.Node map: fields: diff --git a/client-go/applyconfigurations/utils.go b/client-go/applyconfigurations/utils.go index e2adab31..60bfe731 100644 --- a/client-go/applyconfigurations/utils.go +++ b/client-go/applyconfigurations/utils.go @@ -106,8 +106,12 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &corev1alpha1.NetworkInterfaceSpecApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("NetworkInterfaceStatus"): return &corev1alpha1.NetworkInterfaceStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("NetworkPeeringStatus"): + return &corev1alpha1.NetworkPeeringStatusApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("NetworkSpec"): return &corev1alpha1.NetworkSpecApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("NetworkStatus"): + return &corev1alpha1.NetworkStatusApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("Node"): return &corev1alpha1.NodeApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("NodeAffinity"): diff --git a/client-go/openapi/api_violations.report b/client-go/openapi/api_violations.report index f7127c59..3ea3c0cc 100644 --- a/client-go/openapi/api_violations.report +++ b/client-go/openapi/api_violations.report @@ -17,6 +17,7 @@ API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/c API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/core/v1alpha1,NetworkInterfaceStatus,Prefixes API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/core/v1alpha1,NetworkInterfaceStatus,PublicIPs API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/core/v1alpha1,NetworkSpec,PeeredIDs +API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/core/v1alpha1,NetworkStatus,Peerings API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/core/v1alpha1,NodeSelector,NodeSelectorTerms API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/core/v1alpha1,NodeSelectorRequirement,Values API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/core/v1alpha1,NodeSelectorTerm,MatchExpressions diff --git a/client-go/openapi/zz_generated.openapi.go b/client-go/openapi/zz_generated.openapi.go index f338a7cf..25788c9e 100644 --- a/client-go/openapi/zz_generated.openapi.go +++ b/client-go/openapi/zz_generated.openapi.go @@ -78,6 +78,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1.NetworkInterfaceSpec": schema_ironcore_net_api_core_v1alpha1_NetworkInterfaceSpec(ref), "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1.NetworkInterfaceStatus": schema_ironcore_net_api_core_v1alpha1_NetworkInterfaceStatus(ref), "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1.NetworkList": schema_ironcore_net_api_core_v1alpha1_NetworkList(ref), + "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1.NetworkPeeringStatus": schema_ironcore_net_api_core_v1alpha1_NetworkPeeringStatus(ref), "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1.NetworkSpec": schema_ironcore_net_api_core_v1alpha1_NetworkSpec(ref), "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1.NetworkStatus": schema_ironcore_net_api_core_v1alpha1_NetworkStatus(ref), "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1.Node": schema_ironcore_net_api_core_v1alpha1_Node(ref), @@ -2765,6 +2766,35 @@ func schema_ironcore_net_api_core_v1alpha1_NetworkList(ref common.ReferenceCallb } } +func schema_ironcore_net_api_core_v1alpha1_NetworkPeeringStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "NetworkPeeringStatus is the status of a network peering.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "Name is the name of the network peering.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "state": { + SchemaProps: spec.SchemaProps{ + Description: "State represents the network peering state", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"name"}, + }, + }, + } +} + func schema_ironcore_net_api_core_v1alpha1_NetworkSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -2804,8 +2834,26 @@ func schema_ironcore_net_api_core_v1alpha1_NetworkStatus(ref common.ReferenceCal Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "peerings": { + SchemaProps: spec.SchemaProps{ + Description: "Peerings contains the states of the network peerings for the network.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/ironcore-dev/ironcore-net/api/core/v1alpha1.NetworkPeeringStatus"), + }, + }, + }, + }, + }, + }, }, }, + Dependencies: []string{ + "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1.NetworkPeeringStatus"}, } } diff --git a/cmd/apinetlet/main.go b/cmd/apinetlet/main.go index 028f8422..4c96bf5b 100644 --- a/cmd/apinetlet/main.go +++ b/cmd/apinetlet/main.go @@ -200,16 +200,6 @@ func main() { os.Exit(1) } - if err = (&controllers.NetworkPeeringReconciler{ - Client: mgr.GetClient(), - APINetClient: apiNetCluster.GetClient(), - APINetNamespace: apiNetNamespace, - WatchFilterValue: watchFilterValue, - }).SetupWithManager(mgr, apiNetCluster.GetCache()); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "NetworkPeering") - os.Exit(1) - } - if err = (&controllers.NetworkInterfaceReconciler{ Client: mgr.GetClient(), APINetClient: apiNetCluster.GetClient(), diff --git a/docs/concepts/network-lifecycle.md b/docs/concepts/network-lifecycle.md index 787f9f04..c4ed616d 100644 --- a/docs/concepts/network-lifecycle.md +++ b/docs/concepts/network-lifecycle.md @@ -31,13 +31,12 @@ When creating network peering both `ironcore` `Network`s has to specify matching `spec.peerings` referencing each other respectively. A `ironcore` `Network` can be peered with multiple `network`s in any namespcae. -Once specified `apinetlet` `NetworkPeeringController` validates if all the specified `network`s are in -`Available` state,they do exists and have matching `peerings`. +The `apinetlet` `NetworkController` checks if there are any `peeringClaimRefs` +present in `ironcore` `Network`. If yes then get `ironcore-net` `Network` using `UID` of `peeringClaimRef` +and add `spec.ID` of that `ironcore-net` `Network` into `spec.peeredIDs` of current `ironcore-net` `Network`. -If validation is successful, `apinetlet` `NetworkPeeringController` updates `ironcore` `Network` -`status.peerings` with network peering `name`s and `spec.incomingPeerings` with valid -incoming peerings. Also `apinetlet` `NetworkPeeringController` updates `ironcore-net` `Network` -`spec.peeredIDs` with valid peered network's `providerID`'s. +The `apinetlet` `NetworkController` also checks for `status.peerings` in `ironcore` `Network`. +If yes then update `ironcore-net` `Network`s `status.peerings` with `ironcore` `Network`s `status.peerings` Once `ironcore-net` `Network` is updated with `spec.peeredIDs`, `metalnetlet` `NetworkController` updates `metalnet` `Network` `spec.peeredIDs` with corresponding `ironcore-net` `Network` `spec.peeredIDs` \ No newline at end of file diff --git a/internal/apis/core/network_types.go b/internal/apis/core/network_types.go index 743ccd8d..45b97a84 100644 --- a/internal/apis/core/network_types.go +++ b/internal/apis/core/network_types.go @@ -11,10 +11,34 @@ type NetworkSpec struct { // ID is the ID of the network. ID string // PeeredIDs are the IDs of networks to peer with. - PeeredIDs []string `json:"peeredIDs,omitempty"` + PeeredIDs []string } type NetworkStatus struct { + // Peerings contains the states of the network peerings for the network. + Peerings []NetworkPeeringStatus +} + +// NetworkState is the state of a network. +// +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 } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/internal/apis/core/v1alpha1/zz_generated.conversion.go b/internal/apis/core/v1alpha1/zz_generated.conversion.go index 39042b19..08d23119 100644 --- a/internal/apis/core/v1alpha1/zz_generated.conversion.go +++ b/internal/apis/core/v1alpha1/zz_generated.conversion.go @@ -608,6 +608,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*v1alpha1.NetworkPeeringStatus)(nil), (*core.NetworkPeeringStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_NetworkPeeringStatus_To_core_NetworkPeeringStatus(a.(*v1alpha1.NetworkPeeringStatus), b.(*core.NetworkPeeringStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.NetworkPeeringStatus)(nil), (*v1alpha1.NetworkPeeringStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_NetworkPeeringStatus_To_v1alpha1_NetworkPeeringStatus(a.(*core.NetworkPeeringStatus), b.(*v1alpha1.NetworkPeeringStatus), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*v1alpha1.NetworkSpec)(nil), (*core.NetworkSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha1_NetworkSpec_To_core_NetworkSpec(a.(*v1alpha1.NetworkSpec), b.(*core.NetworkSpec), scope) }); err != nil { @@ -2177,6 +2187,28 @@ func Convert_core_NetworkList_To_v1alpha1_NetworkList(in *core.NetworkList, out return autoConvert_core_NetworkList_To_v1alpha1_NetworkList(in, out, s) } +func autoConvert_v1alpha1_NetworkPeeringStatus_To_core_NetworkPeeringStatus(in *v1alpha1.NetworkPeeringStatus, out *core.NetworkPeeringStatus, s conversion.Scope) error { + out.Name = in.Name + out.State = core.NetworkPeeringState(in.State) + return nil +} + +// Convert_v1alpha1_NetworkPeeringStatus_To_core_NetworkPeeringStatus is an autogenerated conversion function. +func Convert_v1alpha1_NetworkPeeringStatus_To_core_NetworkPeeringStatus(in *v1alpha1.NetworkPeeringStatus, out *core.NetworkPeeringStatus, s conversion.Scope) error { + return autoConvert_v1alpha1_NetworkPeeringStatus_To_core_NetworkPeeringStatus(in, out, s) +} + +func autoConvert_core_NetworkPeeringStatus_To_v1alpha1_NetworkPeeringStatus(in *core.NetworkPeeringStatus, out *v1alpha1.NetworkPeeringStatus, s conversion.Scope) error { + out.Name = in.Name + out.State = v1alpha1.NetworkPeeringState(in.State) + return nil +} + +// Convert_core_NetworkPeeringStatus_To_v1alpha1_NetworkPeeringStatus is an autogenerated conversion function. +func Convert_core_NetworkPeeringStatus_To_v1alpha1_NetworkPeeringStatus(in *core.NetworkPeeringStatus, out *v1alpha1.NetworkPeeringStatus, s conversion.Scope) error { + return autoConvert_core_NetworkPeeringStatus_To_v1alpha1_NetworkPeeringStatus(in, out, s) +} + func autoConvert_v1alpha1_NetworkSpec_To_core_NetworkSpec(in *v1alpha1.NetworkSpec, out *core.NetworkSpec, s conversion.Scope) error { out.ID = in.ID out.PeeredIDs = *(*[]string)(unsafe.Pointer(&in.PeeredIDs)) @@ -2200,6 +2232,7 @@ func Convert_core_NetworkSpec_To_v1alpha1_NetworkSpec(in *core.NetworkSpec, out } func autoConvert_v1alpha1_NetworkStatus_To_core_NetworkStatus(in *v1alpha1.NetworkStatus, out *core.NetworkStatus, s conversion.Scope) error { + out.Peerings = *(*[]core.NetworkPeeringStatus)(unsafe.Pointer(&in.Peerings)) return nil } @@ -2209,6 +2242,7 @@ func Convert_v1alpha1_NetworkStatus_To_core_NetworkStatus(in *v1alpha1.NetworkSt } func autoConvert_core_NetworkStatus_To_v1alpha1_NetworkStatus(in *core.NetworkStatus, out *v1alpha1.NetworkStatus, s conversion.Scope) error { + out.Peerings = *(*[]v1alpha1.NetworkPeeringStatus)(unsafe.Pointer(&in.Peerings)) return nil } diff --git a/internal/apis/core/zz_generated.deepcopy.go b/internal/apis/core/zz_generated.deepcopy.go index 13cd7b8a..e5ae5004 100644 --- a/internal/apis/core/zz_generated.deepcopy.go +++ b/internal/apis/core/zz_generated.deepcopy.go @@ -1177,7 +1177,7 @@ func (in *Network) DeepCopyInto(out *Network) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - out.Status = in.Status + in.Status.DeepCopyInto(&out.Status) return } @@ -1522,6 +1522,22 @@ func (in *NetworkList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkPeeringStatus) DeepCopyInto(out *NetworkPeeringStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkPeeringStatus. +func (in *NetworkPeeringStatus) DeepCopy() *NetworkPeeringStatus { + if in == nil { + return nil + } + out := new(NetworkPeeringStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NetworkSpec) DeepCopyInto(out *NetworkSpec) { *out = *in @@ -1546,6 +1562,11 @@ func (in *NetworkSpec) DeepCopy() *NetworkSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NetworkStatus) DeepCopyInto(out *NetworkStatus) { *out = *in + if in.Peerings != nil { + in, out := &in.Peerings, &out.Peerings + *out = make([]NetworkPeeringStatus, len(*in)) + copy(*out, *in) + } return } From 36ccb2d980388a1541a0ca6a7c07865c944a59cd Mon Sep 17 00:00:00 2001 From: Kajol Asabe Date: Fri, 5 Apr 2024 18:45:33 +0530 Subject: [PATCH 7/9] update ironcore version and address review comments --- apinetlet/controllers/network_controller.go | 5 +-- .../controllers/network_controller_test.go | 10 ++--- go.mod | 14 +++---- go.sum | 42 +++++++++---------- metalnetlet/controllers/network_controller.go | 2 +- 5 files changed, 35 insertions(+), 38 deletions(-) diff --git a/apinetlet/controllers/network_controller.go b/apinetlet/controllers/network_controller.go index 26cbbcf4..4ebca119 100644 --- a/apinetlet/controllers/network_controller.go +++ b/apinetlet/controllers/network_controller.go @@ -208,9 +208,8 @@ func (r *NetworkReconciler) applyAPINetNetwork(ctx context.Context, log logr.Log var peerings []apinetv1alpha1.NetworkPeeringStatus for _, peering := range network.Status.Peerings { peerings = append(peerings, apinetv1alpha1.NetworkPeeringStatus{ - Name: peering.Name, - // TODO remove below comment after merging ironcore PR #1026 - // State: peering.State, + Name: peering.Name, + State: apinetv1alpha1.NetworkPeeringStatePending, }) } apiNetNetwork.Status.Peerings = peerings diff --git a/apinetlet/controllers/network_controller_test.go b/apinetlet/controllers/network_controller_test.go index 4b34349b..10120afe 100644 --- a/apinetlet/controllers/network_controller_test.go +++ b/apinetlet/controllers/network_controller_test.go @@ -167,9 +167,8 @@ var _ = Describe("NetworkController", func() { UID: network2.UID, }} network1.Status.Peerings = []networkingv1alpha1.NetworkPeeringStatus{{ - Name: network1.Spec.Peerings[0].Name, - // TODO remove below comment after merging ironcore PR #1026 - // State: networkingv1alpha1.NetworkPeeringStatePending, + Name: network1.Spec.Peerings[0].Name, + State: networkingv1alpha1.NetworkPeeringStatePending, }} Expect(k8sClient.Patch(ctx, network1, client.MergeFrom(baseNetwork1))).To(Succeed()) @@ -180,9 +179,8 @@ var _ = Describe("NetworkController", func() { UID: network1.UID, }} network2.Status.Peerings = []networkingv1alpha1.NetworkPeeringStatus{{ - Name: network2.Spec.Peerings[0].Name, - // TODO remove below comment after merging ironcore PR #1026 - // State: networkingv1alpha1.NetworkPeeringStatePending, + Name: network2.Spec.Peerings[0].Name, + State: networkingv1alpha1.NetworkPeeringStatePending, }} Expect(k8sClient.Patch(ctx, network2, client.MergeFrom(baseNetwork2))).To(Succeed()) diff --git a/go.mod b/go.mod index c9f2dd61..8ed6473a 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/go-logr/logr v1.4.1 github.com/google/uuid v1.6.0 github.com/ironcore-dev/controller-utils v0.9.3 - github.com/ironcore-dev/ironcore v0.1.2-0.20240116114543-d37a145029e7 + github.com/ironcore-dev/ironcore v0.1.2-0.20240405075112-2f56f2cc77c8 github.com/ironcore-dev/metalnet v0.3.8 github.com/onsi/ginkgo/v2 v2.17.3 github.com/onsi/gomega v1.33.1 @@ -90,7 +90,7 @@ require ( go.uber.org/zap v1.26.0 // indirect golang.org/x/crypto v0.22.0 // indirect golang.org/x/net v0.24.0 // indirect - golang.org/x/oauth2 v0.14.0 // indirect + golang.org/x/oauth2 v0.16.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.19.0 // indirect golang.org/x/term v0.19.0 // indirect @@ -99,10 +99,10 @@ require ( golang.org/x/tools v0.20.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect - google.golang.org/grpc v1.61.1 // indirect + google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect + google.golang.org/grpc v1.62.1 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect @@ -110,7 +110,7 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apiextensions-apiserver v0.29.2 // indirect k8s.io/kms v0.29.4 // indirect - k8s.io/kube-aggregator v0.29.0 // indirect + k8s.io/kube-aggregator v0.29.3 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/yaml v1.4.0 // indirect diff --git a/go.sum b/go.sum index 9dd7ac62..526204c5 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,4 @@ -cloud.google.com/go v0.110.10 h1:LXy9GEO+timppncPIAZoOj3l58LIU9k+kn48AN7IO3Y= +cloud.google.com/go v0.112.0 h1:tpFCD7hpHFlQ8yPwT3x+QeXqc2T6+n6T+hmABHfDUSM= cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= @@ -19,8 +19,8 @@ github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqy github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY= -github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= +github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= @@ -34,8 +34,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= -github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= +github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= +github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.8.0 h1:lRj6N9Nci7MvzrXuX6HFzU8XjmhPiXPlsKEy1u0KQro= @@ -64,8 +64,8 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= -github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= +github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= +github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= @@ -105,8 +105,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/ironcore-dev/controller-utils v0.9.3 h1:sTrnxSzX5RrLf4B8KrAH2axSC+gxfJXphkV6df2GSsw= github.com/ironcore-dev/controller-utils v0.9.3/go.mod h1:djKnxDs0Hwxhhc0VmVY8tZnrOrElvrRV2jov/LiCZ2Y= -github.com/ironcore-dev/ironcore v0.1.2-0.20240116114543-d37a145029e7 h1:Lr/KEpJAW4+TozdduPwXRYMO0fffk7DvOf/r93TKz0E= -github.com/ironcore-dev/ironcore v0.1.2-0.20240116114543-d37a145029e7/go.mod h1:cTjq3AobNNQg/U/bJwrk+JYrX5o0izrQygtIB14Riaw= +github.com/ironcore-dev/ironcore v0.1.2-0.20240405075112-2f56f2cc77c8 h1:/4ZxKKHtp13IdHchNBH3gcrmBYio+wqy33CG02LbcYI= +github.com/ironcore-dev/ironcore v0.1.2-0.20240405075112-2f56f2cc77c8/go.mod h1:IL5p0+EyhA0cSUHQD3R9v81H5BDzQszp2jdsOj3+jD4= github.com/ironcore-dev/metalnet v0.3.8 h1:W5bE7496zl4D2Jo4mgv8ql6YwUHLK6TxZPHutncHgLc= github.com/ironcore-dev/metalnet v0.3.8/go.mod h1:aZU9zJjoiTqTROOBb1QldXfK1Jd4TMV6SuVnPCsvVJE= github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= @@ -246,8 +246,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= -golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0= -golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= +golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= +golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -290,14 +290,14 @@ gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= -google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ= -google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= -google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo= -google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA= -google.golang.org/grpc v1.61.1 h1:kLAiWrZs7YeDM6MumDe7m3y4aM6wacLzM1Y/wiLP9XY= -google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= +google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ= +google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= +google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 h1:Lj5rbfG876hIAYFjqiJnPHfhXbv+nzTWfm04Fg/XSVU= +google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 h1:AjyfHzEPEFp/NpvfN5g+KDla3EMojjhRVZc1i7cj+oM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= +google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= +google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= @@ -333,8 +333,8 @@ k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kms v0.29.4 h1:cFGEoCLwoXk/eqYZppLZxybCdmEWeRKMCbm9f13IdRQ= k8s.io/kms v0.29.4/go.mod h1:vWVImKkJd+1BQY4tBwdfSwjQBiLrnbNtHADcDEDQFtk= -k8s.io/kube-aggregator v0.29.0 h1:N4fmtePxOZ+bwiK1RhVEztOU+gkoVkvterHgpwAuiTw= -k8s.io/kube-aggregator v0.29.0/go.mod h1:bjatII63ORkFg5yUFP2qm2OC49R0wwxZhRVIyJ4Z4X0= +k8s.io/kube-aggregator v0.29.3 h1:5KvTyFN8sQq2imq8tMAHWEKoE64Zg9WSMaGX78KV6ps= +k8s.io/kube-aggregator v0.29.3/go.mod h1:xGJqV/SJJ1fbwTGfQLAZfwgqX1EMoaqfotDTkDrqqSk= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ= diff --git a/metalnetlet/controllers/network_controller.go b/metalnetlet/controllers/network_controller.go index 986a90ed..b8984a60 100644 --- a/metalnetlet/controllers/network_controller.go +++ b/metalnetlet/controllers/network_controller.go @@ -148,7 +148,7 @@ func (r *NetworkReconciler) reconcile(ctx context.Context, log logr.Logger, netw for _, peeredId := range network.Spec.PeeredIDs { id, err := networkid.ParseVNI(peeredId) if err != nil { - return ctrl.Result{}, fmt.Errorf("error converting network peering ID to int32: %w", err) + return ctrl.Result{}, fmt.Errorf("failed to parse peered network ID: %w", err) } metalnetNetwork.Spec.PeeredIDs = append(metalnetNetwork.Spec.PeeredIDs, int32(id)) From e0edc96834fa6dc252eab4dd55731f763e6c4585 Mon Sep 17 00:00:00 2001 From: Kajol Asabe Date: Mon, 6 May 2024 19:12:11 +0530 Subject: [PATCH 8/9] modify apinetlet and metalnetlet network controllers for peering status --- api/core/v1alpha1/network_types.go | 22 ++- api/core/v1alpha1/zz_generated.deepcopy.go | 22 ++- apinetlet/controllers/conversion.go | 18 +++ apinetlet/controllers/network_controller.go | 29 ++-- .../controllers/network_controller_test.go | 46 ++++++- .../core/v1alpha1/networkpeering.go | 35 +++++ .../core/v1alpha1/networkpeeringstatus.go | 10 +- .../core/v1alpha1/networkspec.go | 15 +- .../applyconfigurations/internal/internal.go | 17 ++- client-go/applyconfigurations/utils.go | 2 + client-go/openapi/api_violations.report | 2 +- client-go/openapi/zz_generated.openapi.go | 50 +++++-- config/apiserver/rbac/metalnetlet_role.yaml | 8 ++ config/metalnetlet/apinet-rbac/role.yaml | 8 ++ docs/api-reference/core.md | 129 ++++++++++++++++++ go.mod | 16 +-- go.sum | 36 ++--- internal/apis/core/network_types.go | 22 ++- .../core/v1alpha1/zz_generated.conversion.go | 40 +++++- internal/apis/core/zz_generated.deepcopy.go | 22 ++- metalnetlet/controllers/conversion.go | 33 +++-- metalnetlet/controllers/network_controller.go | 38 ++++-- .../controllers/network_controller_test.go | 115 +++++++++++++--- 23 files changed, 608 insertions(+), 127 deletions(-) create mode 100644 client-go/applyconfigurations/core/v1alpha1/networkpeering.go diff --git a/api/core/v1alpha1/network_types.go b/api/core/v1alpha1/network_types.go index dca5ad68..6e097188 100644 --- a/api/core/v1alpha1/network_types.go +++ b/api/core/v1alpha1/network_types.go @@ -10,8 +10,16 @@ import ( type NetworkSpec struct { // ID is the ID of the network. ID string `json:"id,omitempty"` - // PeeredIDs are the IDs of networks to peer with. - PeeredIDs []string `json:"peeredIDs,omitempty"` + // Peerings are the network peerings with this network + Peerings []NetworkPeering `json:"peerings,omitempty"` +} + +// NetworkPeering defines a network peering with another network. +type NetworkPeering struct { + // Name is the semantical name of the network peering. + Name string `json:"name"` + // ID is the ID of the network to peer with. + ID string `json:"id"` } type NetworkStatus struct { @@ -29,14 +37,16 @@ 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" + // NetworkPeeringStateReady signals that the network peering is ready. + NetworkPeeringStateReady NetworkPeeringState = "Ready" + // NetworkPeeringStateError signals that the network peering is in error state. + NetworkPeeringStateError NetworkPeeringState = "Error" ) // NetworkPeeringStatus is the status of a network peering. type NetworkPeeringStatus struct { - // Name is the name of the network peering. - Name string `json:"name"` + // ID is the ID of network + ID int32 `json:"id"` // State represents the network peering state State NetworkPeeringState `json:"state,omitempty"` } diff --git a/api/core/v1alpha1/zz_generated.deepcopy.go b/api/core/v1alpha1/zz_generated.deepcopy.go index 6aaf104e..7153a27e 100644 --- a/api/core/v1alpha1/zz_generated.deepcopy.go +++ b/api/core/v1alpha1/zz_generated.deepcopy.go @@ -1522,6 +1522,22 @@ func (in *NetworkList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkPeering) DeepCopyInto(out *NetworkPeering) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkPeering. +func (in *NetworkPeering) DeepCopy() *NetworkPeering { + if in == nil { + return nil + } + out := new(NetworkPeering) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NetworkPeeringStatus) DeepCopyInto(out *NetworkPeeringStatus) { *out = *in @@ -1541,9 +1557,9 @@ func (in *NetworkPeeringStatus) DeepCopy() *NetworkPeeringStatus { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NetworkSpec) DeepCopyInto(out *NetworkSpec) { *out = *in - if in.PeeredIDs != nil { - in, out := &in.PeeredIDs, &out.PeeredIDs - *out = make([]string, len(*in)) + if in.Peerings != nil { + in, out := &in.Peerings, &out.Peerings + *out = make([]NetworkPeering, len(*in)) copy(*out, *in) } return diff --git a/apinetlet/controllers/conversion.go b/apinetlet/controllers/conversion.go index c8663279..8aa8c516 100644 --- a/apinetlet/controllers/conversion.go +++ b/apinetlet/controllers/conversion.go @@ -5,6 +5,8 @@ package controllers import ( "fmt" + "slices" + "strconv" apinetv1alpha1 "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1" "github.com/ironcore-dev/ironcore-net/apimachinery/api/net" @@ -69,3 +71,19 @@ func apiNetNetworkInterfaceStateToNetworkInterfaceState(state apinetv1alpha1.Net return networkingv1alpha1.NetworkInterfaceStatePending } } + +func apiNetNetworkPeeringsStatusToNetworkPeeringsStatus(peerings []apinetv1alpha1.NetworkPeeringStatus, specPeerings []apinetv1alpha1.NetworkPeering) []networkingv1alpha1.NetworkPeeringStatus { + networkPeeringsStatus := []networkingv1alpha1.NetworkPeeringStatus{} + for _, peering := range peerings { + idx := slices.IndexFunc(specPeerings, func(specPeering apinetv1alpha1.NetworkPeering) bool { + return specPeering.ID == strconv.Itoa(int(peering.ID)) + }) + if idx != -1 { + networkPeeringsStatus = append(networkPeeringsStatus, networkingv1alpha1.NetworkPeeringStatus{ + Name: specPeerings[idx].Name, + State: networkingv1alpha1.NetworkPeeringState(peering.State), + }) + } + } + return networkPeeringsStatus +} diff --git a/apinetlet/controllers/network_controller.go b/apinetlet/controllers/network_controller.go index 4ebca119..be361120 100644 --- a/apinetlet/controllers/network_controller.go +++ b/apinetlet/controllers/network_controller.go @@ -6,6 +6,7 @@ package controllers import ( "context" "fmt" + "slices" "github.com/go-logr/logr" "github.com/ironcore-dev/controller-utils/clientutils" @@ -114,9 +115,10 @@ func (r *NetworkReconciler) delete(ctx context.Context, log logr.Logger, network return ctrl.Result{Requeue: true}, nil } -func (r *NetworkReconciler) updateNetworkStatus(ctx context.Context, network *networkingv1alpha1.Network, state networkingv1alpha1.NetworkState) error { +func (r *NetworkReconciler) updateNetworkStatus(ctx context.Context, network *networkingv1alpha1.Network, apiNetNetwork *apinetv1alpha1.Network, state networkingv1alpha1.NetworkState) error { networkBase := network.DeepCopy() network.Status.State = state + network.Status.Peerings = apiNetNetworkPeeringsStatusToNetworkPeeringsStatus(apiNetNetwork.Status.Peerings, apiNetNetwork.Spec.Peerings) if err := r.Status().Patch(ctx, network, client.MergeFrom(networkBase)); err != nil { return fmt.Errorf("unable to patch network: %w", err) } @@ -139,7 +141,7 @@ func (r *NetworkReconciler) reconcile(ctx context.Context, log logr.Logger, netw apiNetNetwork, err := r.applyAPINetNetwork(ctx, log, network) if err != nil { if network.Status.State != networkingv1alpha1.NetworkStateAvailable { - if err := r.updateNetworkStatus(ctx, network, networkingv1alpha1.NetworkStatePending); err != nil { + if err := r.updateNetworkStatus(ctx, network, apiNetNetwork, networkingv1alpha1.NetworkStatePending); err != nil { log.Error(err, "Error updating network state") } } @@ -159,9 +161,10 @@ func (r *NetworkReconciler) reconcile(ctx context.Context, log logr.Logger, netw } log.V(1).Info("Updating network status") - if err := r.updateNetworkStatus(ctx, network, networkingv1alpha1.NetworkStateAvailable); err != nil { + if err := r.updateNetworkStatus(ctx, network, apiNetNetwork, networkingv1alpha1.NetworkStateAvailable); err != nil { return ctrl.Result{}, fmt.Errorf("error updating network status: %w", err) } + log.V(1).Info("Updated network status") log.V(1).Info("Reconciled") return ctrl.Result{}, nil @@ -193,7 +196,7 @@ func (r *NetworkReconciler) applyAPINetNetwork(ctx context.Context, log logr.Log }, } - var peeredIDs []string + var peerings []apinetv1alpha1.NetworkPeering for _, peeringClaimRef := range network.Spec.PeeringClaimRefs { log.V(1).Info("Get apinet network for target network") targetApinetNetwork := &apinetv1alpha1.Network{} @@ -201,18 +204,18 @@ func (r *NetworkReconciler) applyAPINetNetwork(ctx context.Context, log logr.Log log.V(1).Info("target apinet network is not created yet") break } - peeredIDs = append(peeredIDs, targetApinetNetwork.Spec.ID) - } - apiNetNetwork.Spec.PeeredIDs = peeredIDs - var peerings []apinetv1alpha1.NetworkPeeringStatus - for _, peering := range network.Status.Peerings { - peerings = append(peerings, apinetv1alpha1.NetworkPeeringStatus{ - Name: peering.Name, - State: apinetv1alpha1.NetworkPeeringStatePending, + idx := slices.IndexFunc(network.Spec.Peerings, func(peering networkingv1alpha1.NetworkPeering) bool { + return peering.NetworkRef.Name == peeringClaimRef.Name }) + if idx != -1 { + peerings = append(peerings, apinetv1alpha1.NetworkPeering{ + Name: network.Spec.Peerings[idx].Name, + ID: targetApinetNetwork.Spec.ID, + }) + } } - apiNetNetwork.Status.Peerings = peerings + apiNetNetwork.Spec.Peerings = peerings log.V(1).Info("Applying APINet network") if err := r.APINetClient.Patch(ctx, apiNetNetwork, client.Apply, fieldOwner, client.ForceOwnership); err != nil { diff --git a/apinetlet/controllers/network_controller_test.go b/apinetlet/controllers/network_controller_test.go index 10120afe..f4d0a704 100644 --- a/apinetlet/controllers/network_controller_test.go +++ b/apinetlet/controllers/network_controller_test.go @@ -4,6 +4,8 @@ package controllers import ( + "strconv" + apinetv1alpha1 "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1" apinetletclient "github.com/ironcore-dev/ironcore-net/apinetlet/client" "github.com/ironcore-dev/ironcore-net/apinetlet/provider" @@ -184,13 +186,51 @@ var _ = Describe("NetworkController", func() { }} Expect(k8sClient.Patch(ctx, network2, client.MergeFrom(baseNetwork2))).To(Succeed()) - By("ensuring apinet network peeredIDs are updated") + By("ensuring apinet network spec peerings are updated") Eventually(Object(apiNetNetwork1)).Should(SatisfyAll( - HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork2.Spec.ID)), + HaveField("Spec.Peerings", ConsistOf(apinetv1alpha1.NetworkPeering{ + Name: network1.Spec.Peerings[0].Name, + ID: apiNetNetwork2.Spec.ID, + })), )) Eventually(Object(apiNetNetwork2)).Should(SatisfyAll( - HaveField("Spec.PeeredIDs", ConsistOf(apiNetNetwork1.Spec.ID)), + HaveField("Spec.Peerings", ConsistOf(apinetv1alpha1.NetworkPeering{ + Name: network2.Spec.Peerings[0].Name, + ID: apiNetNetwork1.Spec.ID, + })), + )) + + By("patching apinet network peering status") + apiNetNetwork2ID, _ := strconv.Atoi(apiNetNetwork2.Spec.ID) + Eventually(UpdateStatus(apiNetNetwork1, func() { + apiNetNetwork1.Status.Peerings = []apinetv1alpha1.NetworkPeeringStatus{{ + ID: int32(apiNetNetwork2ID), + State: apinetv1alpha1.NetworkPeeringStateReady, + }} + })).Should(Succeed()) + + apiNetNetwork1ID, _ := strconv.Atoi(apiNetNetwork1.Spec.ID) + Eventually(UpdateStatus(apiNetNetwork2, func() { + apiNetNetwork2.Status.Peerings = []apinetv1alpha1.NetworkPeeringStatus{{ + ID: int32(apiNetNetwork1ID), + State: apinetv1alpha1.NetworkPeeringStateReady, + }} + })).Should(Succeed()) + + By("ensuring ironcore networks peering status is updated") + Eventually(Object(network1)).Should(SatisfyAll( + HaveField("Status.Peerings", ConsistOf(networkingv1alpha1.NetworkPeeringStatus{ + Name: network1.Spec.Peerings[0].Name, + State: networkingv1alpha1.NetworkPeeringStateReady, + })), + )) + + Eventually(Object(network2)).Should(SatisfyAll( + HaveField("Status.Peerings", ConsistOf(networkingv1alpha1.NetworkPeeringStatus{ + Name: network2.Spec.Peerings[0].Name, + State: networkingv1alpha1.NetworkPeeringStateReady, + })), )) By("deleting the networks") diff --git a/client-go/applyconfigurations/core/v1alpha1/networkpeering.go b/client-go/applyconfigurations/core/v1alpha1/networkpeering.go new file mode 100644 index 00000000..edc70d76 --- /dev/null +++ b/client-go/applyconfigurations/core/v1alpha1/networkpeering.go @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// NetworkPeeringApplyConfiguration represents an declarative configuration of the NetworkPeering type for use +// with apply. +type NetworkPeeringApplyConfiguration struct { + Name *string `json:"name,omitempty"` + ID *string `json:"id,omitempty"` +} + +// NetworkPeeringApplyConfiguration constructs an declarative configuration of the NetworkPeering type for use with +// apply. +func NetworkPeering() *NetworkPeeringApplyConfiguration { + return &NetworkPeeringApplyConfiguration{} +} + +// WithName sets the Name 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 Name field is set to the value of the last call. +func (b *NetworkPeeringApplyConfiguration) WithName(value string) *NetworkPeeringApplyConfiguration { + b.Name = &value + return b +} + +// WithID sets the ID 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 ID field is set to the value of the last call. +func (b *NetworkPeeringApplyConfiguration) WithID(value string) *NetworkPeeringApplyConfiguration { + b.ID = &value + return b +} diff --git a/client-go/applyconfigurations/core/v1alpha1/networkpeeringstatus.go b/client-go/applyconfigurations/core/v1alpha1/networkpeeringstatus.go index 5e392a4a..68a76fcc 100644 --- a/client-go/applyconfigurations/core/v1alpha1/networkpeeringstatus.go +++ b/client-go/applyconfigurations/core/v1alpha1/networkpeeringstatus.go @@ -12,7 +12,7 @@ import ( // NetworkPeeringStatusApplyConfiguration represents an declarative configuration of the NetworkPeeringStatus type for use // with apply. type NetworkPeeringStatusApplyConfiguration struct { - Name *string `json:"name,omitempty"` + ID *int32 `json:"id,omitempty"` State *v1alpha1.NetworkPeeringState `json:"state,omitempty"` } @@ -22,11 +22,11 @@ func NetworkPeeringStatus() *NetworkPeeringStatusApplyConfiguration { return &NetworkPeeringStatusApplyConfiguration{} } -// WithName sets the Name field in the declarative configuration to the given value +// WithID sets the ID 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 Name field is set to the value of the last call. -func (b *NetworkPeeringStatusApplyConfiguration) WithName(value string) *NetworkPeeringStatusApplyConfiguration { - b.Name = &value +// If called multiple times, the ID field is set to the value of the last call. +func (b *NetworkPeeringStatusApplyConfiguration) WithID(value int32) *NetworkPeeringStatusApplyConfiguration { + b.ID = &value return b } diff --git a/client-go/applyconfigurations/core/v1alpha1/networkspec.go b/client-go/applyconfigurations/core/v1alpha1/networkspec.go index 9b273a31..b8b350a8 100644 --- a/client-go/applyconfigurations/core/v1alpha1/networkspec.go +++ b/client-go/applyconfigurations/core/v1alpha1/networkspec.go @@ -8,8 +8,8 @@ package v1alpha1 // NetworkSpecApplyConfiguration represents an declarative configuration of the NetworkSpec type for use // with apply. type NetworkSpecApplyConfiguration struct { - ID *string `json:"id,omitempty"` - PeeredIDs []string `json:"peeredIDs,omitempty"` + ID *string `json:"id,omitempty"` + Peerings []NetworkPeeringApplyConfiguration `json:"peerings,omitempty"` } // NetworkSpecApplyConfiguration constructs an declarative configuration of the NetworkSpec type for use with @@ -26,12 +26,15 @@ func (b *NetworkSpecApplyConfiguration) WithID(value string) *NetworkSpecApplyCo return b } -// WithPeeredIDs adds the given value to the PeeredIDs field in the declarative configuration +// WithPeerings adds the given value to the Peerings field in the declarative configuration // and returns the receiver, so that objects can be build by chaining "With" function invocations. -// If called multiple times, values provided by each call will be appended to the PeeredIDs field. -func (b *NetworkSpecApplyConfiguration) WithPeeredIDs(values ...string) *NetworkSpecApplyConfiguration { +// If called multiple times, values provided by each call will be appended to the Peerings field. +func (b *NetworkSpecApplyConfiguration) WithPeerings(values ...*NetworkPeeringApplyConfiguration) *NetworkSpecApplyConfiguration { for i := range values { - b.PeeredIDs = append(b.PeeredIDs, values[i]) + if values[i] == nil { + panic("nil value passed to WithPeerings") + } + b.Peerings = append(b.Peerings, *values[i]) } return b } diff --git a/client-go/applyconfigurations/internal/internal.go b/client-go/applyconfigurations/internal/internal.go index cd18f237..27cc8965 100644 --- a/client-go/applyconfigurations/internal/internal.go +++ b/client-go/applyconfigurations/internal/internal.go @@ -766,13 +766,24 @@ var schemaYAML = typed.YAMLObject(`types: - name: state type: scalar: string -- name: com.github.ironcore-dev.ironcore-net.api.core.v1alpha1.NetworkPeeringStatus +- name: com.github.ironcore-dev.ironcore-net.api.core.v1alpha1.NetworkPeering map: fields: + - name: id + type: + scalar: string + default: "" - name: name type: scalar: string default: "" +- name: com.github.ironcore-dev.ironcore-net.api.core.v1alpha1.NetworkPeeringStatus + map: + fields: + - name: id + type: + scalar: numeric + default: 0 - name: state type: scalar: string @@ -782,11 +793,11 @@ var schemaYAML = typed.YAMLObject(`types: - name: id type: scalar: string - - name: peeredIDs + - name: peerings type: list: elementType: - scalar: string + namedType: com.github.ironcore-dev.ironcore-net.api.core.v1alpha1.NetworkPeering elementRelationship: atomic - name: com.github.ironcore-dev.ironcore-net.api.core.v1alpha1.NetworkStatus map: diff --git a/client-go/applyconfigurations/utils.go b/client-go/applyconfigurations/utils.go index 60bfe731..b04cc99a 100644 --- a/client-go/applyconfigurations/utils.go +++ b/client-go/applyconfigurations/utils.go @@ -106,6 +106,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &corev1alpha1.NetworkInterfaceSpecApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("NetworkInterfaceStatus"): return &corev1alpha1.NetworkInterfaceStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("NetworkPeering"): + return &corev1alpha1.NetworkPeeringApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("NetworkPeeringStatus"): return &corev1alpha1.NetworkPeeringStatusApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("NetworkSpec"): diff --git a/client-go/openapi/api_violations.report b/client-go/openapi/api_violations.report index 3ea3c0cc..d538a9ce 100644 --- a/client-go/openapi/api_violations.report +++ b/client-go/openapi/api_violations.report @@ -16,7 +16,7 @@ API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/c API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/core/v1alpha1,NetworkInterfaceStatus,NATIPs API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/core/v1alpha1,NetworkInterfaceStatus,Prefixes API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/core/v1alpha1,NetworkInterfaceStatus,PublicIPs -API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/core/v1alpha1,NetworkSpec,PeeredIDs +API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/core/v1alpha1,NetworkSpec,Peerings API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/core/v1alpha1,NetworkStatus,Peerings API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/core/v1alpha1,NodeSelector,NodeSelectorTerms API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/core/v1alpha1,NodeSelectorRequirement,Values diff --git a/client-go/openapi/zz_generated.openapi.go b/client-go/openapi/zz_generated.openapi.go index 25788c9e..f7b84e7d 100644 --- a/client-go/openapi/zz_generated.openapi.go +++ b/client-go/openapi/zz_generated.openapi.go @@ -78,6 +78,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1.NetworkInterfaceSpec": schema_ironcore_net_api_core_v1alpha1_NetworkInterfaceSpec(ref), "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1.NetworkInterfaceStatus": schema_ironcore_net_api_core_v1alpha1_NetworkInterfaceStatus(ref), "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1.NetworkList": schema_ironcore_net_api_core_v1alpha1_NetworkList(ref), + "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1.NetworkPeering": schema_ironcore_net_api_core_v1alpha1_NetworkPeering(ref), "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1.NetworkPeeringStatus": schema_ironcore_net_api_core_v1alpha1_NetworkPeeringStatus(ref), "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1.NetworkSpec": schema_ironcore_net_api_core_v1alpha1_NetworkSpec(ref), "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1.NetworkStatus": schema_ironcore_net_api_core_v1alpha1_NetworkStatus(ref), @@ -2766,21 +2767,51 @@ func schema_ironcore_net_api_core_v1alpha1_NetworkList(ref common.ReferenceCallb } } -func schema_ironcore_net_api_core_v1alpha1_NetworkPeeringStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_ironcore_net_api_core_v1alpha1_NetworkPeering(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "NetworkPeeringStatus is the status of a network peering.", + Description: "NetworkPeering defines a network peering with another network.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": { SchemaProps: spec.SchemaProps{ - Description: "Name is the name of the network peering.", + Description: "Name is the semantical name of the network peering.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "id": { + SchemaProps: spec.SchemaProps{ + Description: "ID is the ID of the network to peer with.", Default: "", Type: []string{"string"}, Format: "", }, }, + }, + Required: []string{"name", "id"}, + }, + }, + } +} + +func schema_ironcore_net_api_core_v1alpha1_NetworkPeeringStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "NetworkPeeringStatus is the status of a network peering.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "id": { + SchemaProps: spec.SchemaProps{ + Description: "ID is the ID of network", + Default: 0, + Type: []string{"integer"}, + Format: "int32", + }, + }, "state": { SchemaProps: spec.SchemaProps{ Description: "State represents the network peering state", @@ -2789,7 +2820,7 @@ func schema_ironcore_net_api_core_v1alpha1_NetworkPeeringStatus(ref common.Refer }, }, }, - Required: []string{"name"}, + Required: []string{"id"}, }, }, } @@ -2808,16 +2839,15 @@ func schema_ironcore_net_api_core_v1alpha1_NetworkSpec(ref common.ReferenceCallb Format: "", }, }, - "peeredIDs": { + "peerings": { SchemaProps: spec.SchemaProps{ - Description: "PeeredIDs are the IDs of networks to peer with.", + Description: "Peerings are the network peerings with this network", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Default: map[string]interface{}{}, + Ref: ref("github.com/ironcore-dev/ironcore-net/api/core/v1alpha1.NetworkPeering"), }, }, }, @@ -2826,6 +2856,8 @@ func schema_ironcore_net_api_core_v1alpha1_NetworkSpec(ref common.ReferenceCallb }, }, }, + Dependencies: []string{ + "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1.NetworkPeering"}, } } diff --git a/config/apiserver/rbac/metalnetlet_role.yaml b/config/apiserver/rbac/metalnetlet_role.yaml index dd7e35c5..02654ca5 100644 --- a/config/apiserver/rbac/metalnetlet_role.yaml +++ b/config/apiserver/rbac/metalnetlet_role.yaml @@ -137,6 +137,14 @@ rules: verbs: - patch - update +- apiGroups: + - core.apinet.ironcore.dev + resources: + - networks/status + verbs: + - get + - patch + - update - apiGroups: - core.apinet.ironcore.dev resources: diff --git a/config/metalnetlet/apinet-rbac/role.yaml b/config/metalnetlet/apinet-rbac/role.yaml index 53f4ec00..2d4a821d 100644 --- a/config/metalnetlet/apinet-rbac/role.yaml +++ b/config/metalnetlet/apinet-rbac/role.yaml @@ -137,6 +137,14 @@ rules: verbs: - patch - update +- apiGroups: + - core.apinet.ironcore.dev + resources: + - networks/status + verbs: + - get + - patch + - update - apiGroups: - core.apinet.ironcore.dev resources: diff --git a/docs/api-reference/core.md b/docs/api-reference/core.md index 42525204..718f12bd 100644 --- a/docs/api-reference/core.md +++ b/docs/api-reference/core.md @@ -1098,6 +1098,17 @@ string

ID is the ID of the network.

+ + +peeredIDs
+ +[]string + + + +

PeeredIDs are the IDs of networks to peer with.

+ + @@ -3363,6 +3374,85 @@ PCIAddress +

NetworkPeeringState +(string alias)

+

+(Appears on:NetworkPeeringStatus) +

+
+

NetworkPeeringState is the state a NetworkPeering can be in

+
+ + + + + + + + + + + + + + +
ValueDescription

"Error"

NetworkPeeringStateError signals that the network peering is in error state.

+

"Pending"

NetworkPeeringStatePending signals that the network peering is not applied.

+

"Ready"

NetworkPeeringStateReady signals that the network peering is ready.

+
+

NetworkPeeringStatus +

+

+(Appears on:NetworkStatus) +

+
+

NetworkPeeringStatus is the status of a network peering.

+
+ + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+name
+ +string + +
+

Name is the name of the network peering.

+
+id
+ +int32 + +
+

ID is the ID of network

+
+state
+ + +NetworkPeeringState + + +
+

State represents the network peering state

+

NetworkSpec

@@ -3389,8 +3479,24 @@ string

ID is the ID of the network.

+ + +peeredIDs
+ +[]string + + + +

PeeredIDs are the IDs of networks to peer with.

+ + +

NetworkState +(string alias)

+
+

NetworkState is the state of a network.

+

NetworkStatus

@@ -3398,6 +3504,29 @@ string

+ + + + + + + + + + + + + +
FieldDescription
+peerings
+ + +[]NetworkPeeringStatus + + +
+

Peerings contains the states of the network peerings for the network.

+

NodeAffinity

diff --git a/go.mod b/go.mod index 8ed6473a..158e3ad7 100644 --- a/go.mod +++ b/go.mod @@ -7,8 +7,8 @@ require ( github.com/go-logr/logr v1.4.1 github.com/google/uuid v1.6.0 github.com/ironcore-dev/controller-utils v0.9.3 - github.com/ironcore-dev/ironcore v0.1.2-0.20240405075112-2f56f2cc77c8 - github.com/ironcore-dev/metalnet v0.3.8 + github.com/ironcore-dev/ironcore v0.1.2-0.20240422084632-6089137dd0a1 + github.com/ironcore-dev/metalnet v0.3.9-0.20240502160212-b55083c9fb6b github.com/onsi/ginkgo/v2 v2.17.3 github.com/onsi/gomega v1.33.1 github.com/spf13/cobra v1.8.0 @@ -90,7 +90,7 @@ require ( go.uber.org/zap v1.26.0 // indirect golang.org/x/crypto v0.22.0 // indirect golang.org/x/net v0.24.0 // indirect - golang.org/x/oauth2 v0.16.0 // indirect + golang.org/x/oauth2 v0.17.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.19.0 // indirect golang.org/x/term v0.19.0 // indirect @@ -99,10 +99,10 @@ require ( golang.org/x/tools v0.20.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect - google.golang.org/grpc v1.62.1 // indirect + google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/grpc v1.63.2 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect @@ -110,7 +110,7 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apiextensions-apiserver v0.29.2 // indirect k8s.io/kms v0.29.4 // indirect - k8s.io/kube-aggregator v0.29.3 // indirect + k8s.io/kube-aggregator v0.29.4 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/yaml v1.4.0 // indirect diff --git a/go.sum b/go.sum index 526204c5..45f4b33a 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,6 @@ cloud.google.com/go v0.112.0 h1:tpFCD7hpHFlQ8yPwT3x+QeXqc2T6+n6T+hmABHfDUSM= -cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= -cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= +cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg= +cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= @@ -105,10 +105,10 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/ironcore-dev/controller-utils v0.9.3 h1:sTrnxSzX5RrLf4B8KrAH2axSC+gxfJXphkV6df2GSsw= github.com/ironcore-dev/controller-utils v0.9.3/go.mod h1:djKnxDs0Hwxhhc0VmVY8tZnrOrElvrRV2jov/LiCZ2Y= -github.com/ironcore-dev/ironcore v0.1.2-0.20240405075112-2f56f2cc77c8 h1:/4ZxKKHtp13IdHchNBH3gcrmBYio+wqy33CG02LbcYI= -github.com/ironcore-dev/ironcore v0.1.2-0.20240405075112-2f56f2cc77c8/go.mod h1:IL5p0+EyhA0cSUHQD3R9v81H5BDzQszp2jdsOj3+jD4= -github.com/ironcore-dev/metalnet v0.3.8 h1:W5bE7496zl4D2Jo4mgv8ql6YwUHLK6TxZPHutncHgLc= -github.com/ironcore-dev/metalnet v0.3.8/go.mod h1:aZU9zJjoiTqTROOBb1QldXfK1Jd4TMV6SuVnPCsvVJE= +github.com/ironcore-dev/ironcore v0.1.2-0.20240422084632-6089137dd0a1 h1:qt4L/YFsrxNO/ZLGL6zp2LrOVrgfuaSOpv/oYbkNoow= +github.com/ironcore-dev/ironcore v0.1.2-0.20240422084632-6089137dd0a1/go.mod h1:S9vJ69zFNoE0zBzWXeLlscMExfuJDXQrIoaYTGwE3mE= +github.com/ironcore-dev/metalnet v0.3.9-0.20240502160212-b55083c9fb6b h1:bDEdPa4MKhtwLBAiPDa6FWkJjSk3ADLa9+Tz3JaISBU= +github.com/ironcore-dev/metalnet v0.3.9-0.20240502160212-b55083c9fb6b/go.mod h1:aZU9zJjoiTqTROOBb1QldXfK1Jd4TMV6SuVnPCsvVJE= github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -246,8 +246,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= -golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= -golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= +golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= +golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -290,14 +290,14 @@ gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= -google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ= -google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= -google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 h1:Lj5rbfG876hIAYFjqiJnPHfhXbv+nzTWfm04Fg/XSVU= -google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 h1:AjyfHzEPEFp/NpvfN5g+KDla3EMojjhRVZc1i7cj+oM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= -google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= -google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= +google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= +google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= @@ -333,8 +333,8 @@ k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kms v0.29.4 h1:cFGEoCLwoXk/eqYZppLZxybCdmEWeRKMCbm9f13IdRQ= k8s.io/kms v0.29.4/go.mod h1:vWVImKkJd+1BQY4tBwdfSwjQBiLrnbNtHADcDEDQFtk= -k8s.io/kube-aggregator v0.29.3 h1:5KvTyFN8sQq2imq8tMAHWEKoE64Zg9WSMaGX78KV6ps= -k8s.io/kube-aggregator v0.29.3/go.mod h1:xGJqV/SJJ1fbwTGfQLAZfwgqX1EMoaqfotDTkDrqqSk= +k8s.io/kube-aggregator v0.29.4 h1:yT7vYtwIag4G8HNrktYZ3qz6p6oHKronMAXOw4eQ2WQ= +k8s.io/kube-aggregator v0.29.4/go.mod h1:zBfe4iXXmw5HinNgN0JoAu5rpXdyCUvRfG99+FVOd68= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ= diff --git a/internal/apis/core/network_types.go b/internal/apis/core/network_types.go index 45b97a84..cfd999fe 100644 --- a/internal/apis/core/network_types.go +++ b/internal/apis/core/network_types.go @@ -10,8 +10,16 @@ import ( type NetworkSpec struct { // ID is the ID of the network. ID string - // PeeredIDs are the IDs of networks to peer with. - PeeredIDs []string + // Peerings are the network peerings with this network + Peerings []NetworkPeering +} + +// NetworkPeering defines a network peering with another network. +type NetworkPeering struct { + // Name is the semantical name of the network peering. + Name string + // ID is the ID of the network to peer with. + ID string } type NetworkStatus struct { @@ -29,14 +37,16 @@ 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" + // NetworkPeeringStateReady signals that the network peering is ready. + NetworkPeeringStateReady NetworkPeeringState = "Ready" + // NetworkPeeringStateError signals that the network peering is in error state. + NetworkPeeringStateError NetworkPeeringState = "Error" ) // NetworkPeeringStatus is the status of a network peering. type NetworkPeeringStatus struct { - // Name is the name of the network peering. - Name string + // ID is the ID of network + ID int32 `json:"id"` // State represents the network peering state State NetworkPeeringState } diff --git a/internal/apis/core/v1alpha1/zz_generated.conversion.go b/internal/apis/core/v1alpha1/zz_generated.conversion.go index 08d23119..8b88226c 100644 --- a/internal/apis/core/v1alpha1/zz_generated.conversion.go +++ b/internal/apis/core/v1alpha1/zz_generated.conversion.go @@ -608,6 +608,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*v1alpha1.NetworkPeering)(nil), (*core.NetworkPeering)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_NetworkPeering_To_core_NetworkPeering(a.(*v1alpha1.NetworkPeering), b.(*core.NetworkPeering), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.NetworkPeering)(nil), (*v1alpha1.NetworkPeering)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_NetworkPeering_To_v1alpha1_NetworkPeering(a.(*core.NetworkPeering), b.(*v1alpha1.NetworkPeering), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*v1alpha1.NetworkPeeringStatus)(nil), (*core.NetworkPeeringStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha1_NetworkPeeringStatus_To_core_NetworkPeeringStatus(a.(*v1alpha1.NetworkPeeringStatus), b.(*core.NetworkPeeringStatus), scope) }); err != nil { @@ -2187,8 +2197,30 @@ func Convert_core_NetworkList_To_v1alpha1_NetworkList(in *core.NetworkList, out return autoConvert_core_NetworkList_To_v1alpha1_NetworkList(in, out, s) } -func autoConvert_v1alpha1_NetworkPeeringStatus_To_core_NetworkPeeringStatus(in *v1alpha1.NetworkPeeringStatus, out *core.NetworkPeeringStatus, s conversion.Scope) error { +func autoConvert_v1alpha1_NetworkPeering_To_core_NetworkPeering(in *v1alpha1.NetworkPeering, out *core.NetworkPeering, s conversion.Scope) error { + out.Name = in.Name + out.ID = in.ID + return nil +} + +// Convert_v1alpha1_NetworkPeering_To_core_NetworkPeering is an autogenerated conversion function. +func Convert_v1alpha1_NetworkPeering_To_core_NetworkPeering(in *v1alpha1.NetworkPeering, out *core.NetworkPeering, s conversion.Scope) error { + return autoConvert_v1alpha1_NetworkPeering_To_core_NetworkPeering(in, out, s) +} + +func autoConvert_core_NetworkPeering_To_v1alpha1_NetworkPeering(in *core.NetworkPeering, out *v1alpha1.NetworkPeering, s conversion.Scope) error { out.Name = in.Name + out.ID = in.ID + return nil +} + +// Convert_core_NetworkPeering_To_v1alpha1_NetworkPeering is an autogenerated conversion function. +func Convert_core_NetworkPeering_To_v1alpha1_NetworkPeering(in *core.NetworkPeering, out *v1alpha1.NetworkPeering, s conversion.Scope) error { + return autoConvert_core_NetworkPeering_To_v1alpha1_NetworkPeering(in, out, s) +} + +func autoConvert_v1alpha1_NetworkPeeringStatus_To_core_NetworkPeeringStatus(in *v1alpha1.NetworkPeeringStatus, out *core.NetworkPeeringStatus, s conversion.Scope) error { + out.ID = in.ID out.State = core.NetworkPeeringState(in.State) return nil } @@ -2199,7 +2231,7 @@ func Convert_v1alpha1_NetworkPeeringStatus_To_core_NetworkPeeringStatus(in *v1al } func autoConvert_core_NetworkPeeringStatus_To_v1alpha1_NetworkPeeringStatus(in *core.NetworkPeeringStatus, out *v1alpha1.NetworkPeeringStatus, s conversion.Scope) error { - out.Name = in.Name + out.ID = in.ID out.State = v1alpha1.NetworkPeeringState(in.State) return nil } @@ -2211,7 +2243,7 @@ func Convert_core_NetworkPeeringStatus_To_v1alpha1_NetworkPeeringStatus(in *core func autoConvert_v1alpha1_NetworkSpec_To_core_NetworkSpec(in *v1alpha1.NetworkSpec, out *core.NetworkSpec, s conversion.Scope) error { out.ID = in.ID - out.PeeredIDs = *(*[]string)(unsafe.Pointer(&in.PeeredIDs)) + out.Peerings = *(*[]core.NetworkPeering)(unsafe.Pointer(&in.Peerings)) return nil } @@ -2222,7 +2254,7 @@ func Convert_v1alpha1_NetworkSpec_To_core_NetworkSpec(in *v1alpha1.NetworkSpec, func autoConvert_core_NetworkSpec_To_v1alpha1_NetworkSpec(in *core.NetworkSpec, out *v1alpha1.NetworkSpec, s conversion.Scope) error { out.ID = in.ID - out.PeeredIDs = *(*[]string)(unsafe.Pointer(&in.PeeredIDs)) + out.Peerings = *(*[]v1alpha1.NetworkPeering)(unsafe.Pointer(&in.Peerings)) return nil } diff --git a/internal/apis/core/zz_generated.deepcopy.go b/internal/apis/core/zz_generated.deepcopy.go index e5ae5004..aa967534 100644 --- a/internal/apis/core/zz_generated.deepcopy.go +++ b/internal/apis/core/zz_generated.deepcopy.go @@ -1522,6 +1522,22 @@ func (in *NetworkList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkPeering) DeepCopyInto(out *NetworkPeering) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkPeering. +func (in *NetworkPeering) DeepCopy() *NetworkPeering { + if in == nil { + return nil + } + out := new(NetworkPeering) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NetworkPeeringStatus) DeepCopyInto(out *NetworkPeeringStatus) { *out = *in @@ -1541,9 +1557,9 @@ func (in *NetworkPeeringStatus) DeepCopy() *NetworkPeeringStatus { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NetworkSpec) DeepCopyInto(out *NetworkSpec) { *out = *in - if in.PeeredIDs != nil { - in, out := &in.PeeredIDs, &out.PeeredIDs - *out = make([]string, len(*in)) + if in.Peerings != nil { + in, out := &in.Peerings, &out.Peerings + *out = make([]NetworkPeering, len(*in)) copy(*out, *in) } return diff --git a/metalnetlet/controllers/conversion.go b/metalnetlet/controllers/conversion.go index bfce3155..114cc9d2 100644 --- a/metalnetlet/controllers/conversion.go +++ b/metalnetlet/controllers/conversion.go @@ -7,7 +7,7 @@ import ( "fmt" "net/netip" - "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1" + apinetv1alpha1 "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1" "github.com/ironcore-dev/ironcore-net/apimachinery/api/net" "github.com/ironcore-dev/ironcore/utils/generic" utilslices "github.com/ironcore-dev/ironcore/utils/slices" @@ -43,16 +43,16 @@ func ipsIPFamilies(ips []net.IP) []corev1.IPFamily { return utilslices.Map(ips, net.IP.Family) } -func metalnetNetworkInterfaceStateToNetworkInterfaceStatus(mStatus metalnetv1alpha1.NetworkInterfaceState) v1alpha1.NetworkInterfaceState { +func metalnetNetworkInterfaceStateToNetworkInterfaceStatus(mStatus metalnetv1alpha1.NetworkInterfaceState) apinetv1alpha1.NetworkInterfaceState { switch mStatus { case metalnetv1alpha1.NetworkInterfaceStatePending: - return v1alpha1.NetworkInterfaceStatePending + return apinetv1alpha1.NetworkInterfaceStatePending case metalnetv1alpha1.NetworkInterfaceStateReady: - return v1alpha1.NetworkInterfaceStateReady + return apinetv1alpha1.NetworkInterfaceStateReady case metalnetv1alpha1.NetworkInterfaceStateError: - return v1alpha1.NetworkInterfaceStateError + return apinetv1alpha1.NetworkInterfaceStateError default: - return v1alpha1.NetworkInterfaceStatePending + return apinetv1alpha1.NetworkInterfaceStatePending } } @@ -72,18 +72,18 @@ func metalnetIPPrefixesToIPPrefixes(prefixes []metalnetv1alpha1.IPPrefix) []net. return utilslices.Map(prefixes, metalnetIPPrefixToIPPrefix) } -func loadBalancerTypeToMetalnetLoadBalancerType(loadBalancerType v1alpha1.LoadBalancerType) (metalnetv1alpha1.LoadBalancerType, error) { +func loadBalancerTypeToMetalnetLoadBalancerType(loadBalancerType apinetv1alpha1.LoadBalancerType) (metalnetv1alpha1.LoadBalancerType, error) { switch loadBalancerType { - case v1alpha1.LoadBalancerTypePublic: + case apinetv1alpha1.LoadBalancerTypePublic: return metalnetv1alpha1.LoadBalancerTypePublic, nil - case v1alpha1.LoadBalancerTypeInternal: + case apinetv1alpha1.LoadBalancerTypeInternal: return metalnetv1alpha1.LoadBalancerTypeInternal, nil default: return "", fmt.Errorf("unknown load balancer type %q", loadBalancerType) } } -func loadBalancerPortToMetalnetLoadBalancerPort(port v1alpha1.LoadBalancerPort) metalnetv1alpha1.LBPort { +func loadBalancerPortToMetalnetLoadBalancerPort(port apinetv1alpha1.LoadBalancerPort) metalnetv1alpha1.LBPort { protocol := generic.Deref(port.Protocol, corev1.ProtocolTCP) return metalnetv1alpha1.LBPort{ @@ -92,7 +92,7 @@ func loadBalancerPortToMetalnetLoadBalancerPort(port v1alpha1.LoadBalancerPort) } } -func loadBalancerPortsToMetalnetLoadBalancerPorts(ports []v1alpha1.LoadBalancerPort) []metalnetv1alpha1.LBPort { +func loadBalancerPortsToMetalnetLoadBalancerPorts(ports []apinetv1alpha1.LoadBalancerPort) []metalnetv1alpha1.LBPort { return utilslices.Map(ports, loadBalancerPortToMetalnetLoadBalancerPort) } @@ -138,3 +138,14 @@ func workaroundMetalnetNoIPv6NATDetailsToNATDetailsPointer(natDetails []metalnet } return nil } + +func metalnetNetworkPeeringsStatusToNetworkPeeringsStatus(peerings []metalnetv1alpha1.NetworkPeeringStatus) []apinetv1alpha1.NetworkPeeringStatus { + return utilslices.Map(peerings, metalnetNetworkPeeringStatusToNetworkPeeringStatus) +} + +func metalnetNetworkPeeringStatusToNetworkPeeringStatus(peering metalnetv1alpha1.NetworkPeeringStatus) apinetv1alpha1.NetworkPeeringStatus { + return apinetv1alpha1.NetworkPeeringStatus{ + ID: peering.ID, + State: apinetv1alpha1.NetworkPeeringState(peering.State), + } +} diff --git a/metalnetlet/controllers/network_controller.go b/metalnetlet/controllers/network_controller.go index b8984a60..81e19eec 100644 --- a/metalnetlet/controllers/network_controller.go +++ b/metalnetlet/controllers/network_controller.go @@ -9,7 +9,7 @@ import ( "github.com/go-logr/logr" "github.com/ironcore-dev/controller-utils/clientutils" - "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1" + apinetv1alpha1 "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1" metalnetletclient "github.com/ironcore-dev/ironcore-net/metalnetlet/client" metalnetlethandler "github.com/ironcore-dev/ironcore-net/metalnetlet/handler" "github.com/ironcore-dev/ironcore-net/networkid" @@ -35,12 +35,13 @@ type NetworkReconciler struct { //+kubebuilder:rbac:groups="",resources=events,verbs=create;patch //+kubebuilder:rbac:groups=core.apinet.ironcore.dev,resources=networks,verbs=get;list;watch;update;patch //+kubebuilder:rbac:groups=core.apinet.ironcore.dev,resources=networks/finalizers,verbs=update;patch +//+kubebuilder:rbac:groups=core.apinet.ironcore.dev,resources=networks/status,verbs=get;update;patch //+cluster=metalnet:kubebuilder:rbac:groups=networking.metalnet.ironcore.dev,resources=networks,verbs=get;list;watch;create;update;patch;delete;deletecollection func (r *NetworkReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { log := ctrl.LoggerFrom(ctx) - network := &v1alpha1.Network{} + network := &apinetv1alpha1.Network{} if err := r.Get(ctx, req.NamespacedName, network); err != nil { if !apierrors.IsNotFound(err) { return ctrl.Result{}, fmt.Errorf("error getting network: %w", err) @@ -57,7 +58,7 @@ func (r *NetworkReconciler) deleteGone(ctx context.Context, log logr.Logger, net log.V(1).Info("Deleting all metalnet networks that match the network label") if err := r.MetalnetClient.DeleteAllOf(ctx, &metalnetv1alpha1.Network{}, client.InNamespace(r.MetalnetNamespace), - metalnetletclient.MatchingSourceKeyLabels(r.Scheme(), r.RESTMapper(), networkKey, &v1alpha1.Network{}), + metalnetletclient.MatchingSourceKeyLabels(r.Scheme(), r.RESTMapper(), networkKey, &apinetv1alpha1.Network{}), ); err != nil { return ctrl.Result{}, fmt.Errorf("error deleting metalnet networks matching network label: %w", err) } @@ -66,14 +67,14 @@ func (r *NetworkReconciler) deleteGone(ctx context.Context, log logr.Logger, net return ctrl.Result{}, nil } -func (r *NetworkReconciler) reconcileExists(ctx context.Context, log logr.Logger, network *v1alpha1.Network) (ctrl.Result, error) { +func (r *NetworkReconciler) reconcileExists(ctx context.Context, log logr.Logger, network *apinetv1alpha1.Network) (ctrl.Result, error) { if !network.DeletionTimestamp.IsZero() { return r.delete(ctx, log, network) } return r.reconcile(ctx, log, network) } -func (r *NetworkReconciler) delete(ctx context.Context, log logr.Logger, network *v1alpha1.Network) (ctrl.Result, error) { +func (r *NetworkReconciler) delete(ctx context.Context, log logr.Logger, network *apinetv1alpha1.Network) (ctrl.Result, error) { log.V(1).Info("Delete") if !controllerutil.ContainsFinalizer(network, PartitionFinalizer(r.PartitionName)) { @@ -109,7 +110,16 @@ func (r *NetworkReconciler) delete(ctx context.Context, log logr.Logger, network return ctrl.Result{}, nil } -func (r *NetworkReconciler) reconcile(ctx context.Context, log logr.Logger, network *v1alpha1.Network) (ctrl.Result, error) { +func (r *NetworkReconciler) updateApinetNetworkStatus(ctx context.Context, network *apinetv1alpha1.Network, metalnetNetwork *metalnetv1alpha1.Network) error { + networkBase := network.DeepCopy() + network.Status.Peerings = metalnetNetworkPeeringsStatusToNetworkPeeringsStatus(metalnetNetwork.Status.Peerings) + if err := r.Status().Patch(ctx, network, client.MergeFrom(networkBase)); err != nil { + return fmt.Errorf("unable to patch network: %w", err) + } + return nil +} + +func (r *NetworkReconciler) reconcile(ctx context.Context, log logr.Logger, network *apinetv1alpha1.Network) (ctrl.Result, error) { log.V(1).Info("Reconcile") vni, err := networkid.ParseVNI(network.Spec.ID) @@ -145,13 +155,13 @@ func (r *NetworkReconciler) reconcile(ctx context.Context, log logr.Logger, netw }, } - for _, peeredId := range network.Spec.PeeredIDs { - id, err := networkid.ParseVNI(peeredId) + for _, peering := range network.Spec.Peerings { + id, err := networkid.ParseVNI(peering.ID) if err != nil { return ctrl.Result{}, fmt.Errorf("failed to parse peered network ID: %w", err) } - metalnetNetwork.Spec.PeeredIDs = append(metalnetNetwork.Spec.PeeredIDs, int32(id)) + metalnetNetwork.Spec.PeeredIDs = append(metalnetNetwork.Spec.PeeredIDs, id) } if err := r.MetalnetClient.Patch(ctx, metalnetNetwork, client.Apply, MetalnetFieldOwner, client.ForceOwnership); err != nil { @@ -159,6 +169,12 @@ func (r *NetworkReconciler) reconcile(ctx context.Context, log logr.Logger, netw } log.V(1).Info("Applied metalnet network") + log.V(1).Info("Updating apinet network status") + if err := r.updateApinetNetworkStatus(ctx, network, metalnetNetwork); err != nil { + return ctrl.Result{}, fmt.Errorf("error updating apinet networkstatus: %w", err) + } + log.V(1).Info("Updated apinet network status") + log.V(1).Info("Reconciled") return ctrl.Result{}, nil } @@ -166,11 +182,11 @@ func (r *NetworkReconciler) reconcile(ctx context.Context, log logr.Logger, netw func (r *NetworkReconciler) SetupWithManager(mgr ctrl.Manager, metalnetCache cache.Cache) error { return ctrl.NewControllerManagedBy(mgr). For( - &v1alpha1.Network{}, + &apinetv1alpha1.Network{}, ). WatchesRawSource( source.Kind(metalnetCache, &metalnetv1alpha1.Network{}), - metalnetlethandler.EnqueueRequestForSource(r.Scheme(), r.RESTMapper(), &v1alpha1.Network{}), + metalnetlethandler.EnqueueRequestForSource(r.Scheme(), r.RESTMapper(), &apinetv1alpha1.Network{}), ). Complete(r) } diff --git a/metalnetlet/controllers/network_controller_test.go b/metalnetlet/controllers/network_controller_test.go index 0e6e9105..a50c117a 100644 --- a/metalnetlet/controllers/network_controller_test.go +++ b/metalnetlet/controllers/network_controller_test.go @@ -4,13 +4,15 @@ package controllers import ( - "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1" + apinetv1alpha1 "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1" "github.com/ironcore-dev/ironcore-net/networkid" . "github.com/ironcore-dev/ironcore/utils/testing" metalnetv1alpha1 "github.com/ironcore-dev/metalnet/api/v1alpha1" . "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" ) @@ -19,35 +21,114 @@ var _ = Describe("NetworkController", func() { metalnetNs := SetupNamespace(&k8sClient) SetupTest(metalnetNs) - It("should create a metalnet network for a network", func(ctx SpecContext) { - By("creating a network") - network := &v1alpha1.Network{ + It("should create metalnet networks for apinet networks with peerings", func(ctx SpecContext) { + By("creating a apinet network-1") + network1 := &apinetv1alpha1.Network{ ObjectMeta: metav1.ObjectMeta{ - Namespace: ns.Name, - GenerateName: "network-", + Namespace: ns.Name, + Name: "network-1", }, - Spec: v1alpha1.NetworkSpec{ - PeeredIDs: []string{"123456", "234567"}, + } + Expect(k8sClient.Create(ctx, network1)).To(Succeed()) + + By("creating a apinet network-2") + network2 := &apinetv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns.Name, + Name: "network-2", }, } - Expect(k8sClient.Create(ctx, network)).To(Succeed()) + Expect(k8sClient.Create(ctx, network2)).To(Succeed()) + + By("updating apinet networks spec with peerings") + baseNetwork1 := network1.DeepCopy() + network1.Spec.Peerings = []apinetv1alpha1.NetworkPeering{{ + Name: "peering-1", + ID: network2.Spec.ID}} + Expect(k8sClient.Patch(ctx, network1, client.MergeFrom(baseNetwork1))).To(Succeed()) + + baseNetwork2 := network2.DeepCopy() + network2.Spec.Peerings = []apinetv1alpha1.NetworkPeering{{ + Name: "peering-1", + ID: network1.Spec.ID}} + Expect(k8sClient.Patch(ctx, network2, client.MergeFrom(baseNetwork2))).To(Succeed()) + + By("parsing the VNI of network-1") + network1Vni, err := networkid.ParseVNI(network1.Spec.ID) + Expect(err).NotTo(HaveOccurred()) - By("parsing the VNI") - vni, err := networkid.ParseVNI(network.Spec.ID) + By("parsing the VNI of network-2") + network2Vni, err := networkid.ParseVNI(network2.Spec.ID) Expect(err).NotTo(HaveOccurred()) - By("waiting for the metalnet network to be created") - metalnetNetwork := &metalnetv1alpha1.Network{ + By("waiting for the metalnet networks to be created") + metalnetNetwork1 := &metalnetv1alpha1.Network{ ObjectMeta: metav1.ObjectMeta{ Namespace: metalnetNs.Name, - Name: string(network.UID), + Name: string(network1.UID), }, } - Eventually(Object(metalnetNetwork)).Should(SatisfyAll( + Eventually(Object(metalnetNetwork1)).Should(SatisfyAll( HaveField("Spec", metalnetv1alpha1.NetworkSpec{ - ID: vni, - PeeredIDs: []int32{123456, 234567}, + ID: network1Vni, + PeeredIDs: []int32{network2Vni}, }), )) + + metalnetNetwork2 := &metalnetv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metalnetNs.Name, + Name: string(network2.UID), + }, + } + Eventually(Object(metalnetNetwork2)).Should(SatisfyAll( + HaveField("Spec", metalnetv1alpha1.NetworkSpec{ + ID: network2Vni, + PeeredIDs: []int32{network1Vni}, + }), + )) + + By("updating status of metalnet network peerings") + Eventually(UpdateStatus(metalnetNetwork1, func() { + metalnetNetwork1.Status.Peerings = []metalnetv1alpha1.NetworkPeeringStatus{{ + ID: network2Vni, + State: metalnetv1alpha1.NetworkPeeringStateReady, + }} + })).Should(Succeed()) + + Eventually(UpdateStatus(metalnetNetwork2, func() { + metalnetNetwork2.Status.Peerings = []metalnetv1alpha1.NetworkPeeringStatus{{ + ID: network1Vni, + State: metalnetv1alpha1.NetworkPeeringStateReady, + }} + })).Should(Succeed()) + + By("ensuring apinet network status peerings are also updated") + Eventually(Object(network1)).Should(SatisfyAll( + HaveField("Status.Peerings", []apinetv1alpha1.NetworkPeeringStatus{{ + ID: network2Vni, + State: apinetv1alpha1.NetworkPeeringStateReady, + }}), + )) + + Eventually(Object(network2)).Should(SatisfyAll( + HaveField("Status.Peerings", []apinetv1alpha1.NetworkPeeringStatus{{ + ID: network1Vni, + State: apinetv1alpha1.NetworkPeeringStateReady, + }}), + )) + + 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)) + + By("asserting the corresponding apinet network is gone as well") + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(metalnetNetwork1), metalnetNetwork1)).To(Satisfy(apierrors.IsNotFound)) + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(metalnetNetwork2), metalnetNetwork2)).To(Satisfy(apierrors.IsNotFound)) + }) }) From 950a19bdca59f20a2fad240b6cd78035ec5cdcf9 Mon Sep 17 00:00:00 2001 From: Kajol Asabe Date: Tue, 14 May 2024 17:59:24 +0530 Subject: [PATCH 9/9] update ironcore dependency --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 158e3ad7..036e43a3 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/go-logr/logr v1.4.1 github.com/google/uuid v1.6.0 github.com/ironcore-dev/controller-utils v0.9.3 - github.com/ironcore-dev/ironcore v0.1.2-0.20240422084632-6089137dd0a1 + github.com/ironcore-dev/ironcore v0.1.2-0.20240514120326-51392fa00b86 github.com/ironcore-dev/metalnet v0.3.9-0.20240502160212-b55083c9fb6b github.com/onsi/ginkgo/v2 v2.17.3 github.com/onsi/gomega v1.33.1 @@ -92,7 +92,7 @@ require ( golang.org/x/net v0.24.0 // indirect golang.org/x/oauth2 v0.17.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.19.0 // indirect + golang.org/x/sys v0.20.0 // indirect golang.org/x/term v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect diff --git a/go.sum b/go.sum index 45f4b33a..665d9dfc 100644 --- a/go.sum +++ b/go.sum @@ -105,8 +105,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/ironcore-dev/controller-utils v0.9.3 h1:sTrnxSzX5RrLf4B8KrAH2axSC+gxfJXphkV6df2GSsw= github.com/ironcore-dev/controller-utils v0.9.3/go.mod h1:djKnxDs0Hwxhhc0VmVY8tZnrOrElvrRV2jov/LiCZ2Y= -github.com/ironcore-dev/ironcore v0.1.2-0.20240422084632-6089137dd0a1 h1:qt4L/YFsrxNO/ZLGL6zp2LrOVrgfuaSOpv/oYbkNoow= -github.com/ironcore-dev/ironcore v0.1.2-0.20240422084632-6089137dd0a1/go.mod h1:S9vJ69zFNoE0zBzWXeLlscMExfuJDXQrIoaYTGwE3mE= +github.com/ironcore-dev/ironcore v0.1.2-0.20240514120326-51392fa00b86 h1:wz0q5+UJGbq9fmn2SKLgECTXVirgryMG6Mdo43apksk= +github.com/ironcore-dev/ironcore v0.1.2-0.20240514120326-51392fa00b86/go.mod h1:JO7dJQqi9iaQcRgCIpyHe3l5bh69ypnzfFnSuu8N+8E= github.com/ironcore-dev/metalnet v0.3.9-0.20240502160212-b55083c9fb6b h1:bDEdPa4MKhtwLBAiPDa6FWkJjSk3ADLa9+Tz3JaISBU= github.com/ironcore-dev/metalnet v0.3.9-0.20240502160212-b55083c9fb6b/go.mod h1:aZU9zJjoiTqTROOBb1QldXfK1Jd4TMV6SuVnPCsvVJE= github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= @@ -261,8 +261,8 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=