From 6de703a05100a3c4a2034ba276482b6e1926e4df Mon Sep 17 00:00:00 2001 From: Kajol Asabe <114986456+kasabe28@users.noreply.github.com> Date: Fri, 11 Oct 2024 14:57:15 +0530 Subject: [PATCH] Add partition wise network peering status in apinet `Network` resource (#327) --- api/core/v1alpha1/network_types.go | 2 +- api/core/v1alpha1/zz_generated.deepcopy.go | 14 ++- apinetlet/controllers/conversion.go | 43 +++++---- apinetlet/controllers/network_controller.go | 72 +++++++++----- .../controllers/network_controller_test.go | 12 ++- .../core/v1alpha1/networkstatus.go | 23 +++-- .../applyconfigurations/internal/internal.go | 8 +- client-go/openapi/api_violations.report | 1 - client-go/openapi/zz_generated.openapi.go | 16 +++- docs/api-reference/core.md | 11 +-- internal/apis/core/network_types.go | 2 +- .../core/v1alpha1/zz_generated.conversion.go | 4 +- internal/apis/core/zz_generated.deepcopy.go | 14 ++- metalnetlet/controllers/network_controller.go | 94 +++++++++++++------ .../controllers/network_controller_test.go | 8 +- 15 files changed, 216 insertions(+), 108 deletions(-) diff --git a/api/core/v1alpha1/network_types.go b/api/core/v1alpha1/network_types.go index 7ce301c1..c525f4b3 100644 --- a/api/core/v1alpha1/network_types.go +++ b/api/core/v1alpha1/network_types.go @@ -36,7 +36,7 @@ type PeeringPrefix struct { type NetworkStatus struct { // Peerings contains the states of the network peerings for the network. - Peerings []NetworkPeeringStatus `json:"peerings,omitempty"` + Peerings map[string][]NetworkPeeringStatus `json:"peerings,omitempty"` } // NetworkState is the state of a network. diff --git a/api/core/v1alpha1/zz_generated.deepcopy.go b/api/core/v1alpha1/zz_generated.deepcopy.go index 322f2296..a8807fcb 100644 --- a/api/core/v1alpha1/zz_generated.deepcopy.go +++ b/api/core/v1alpha1/zz_generated.deepcopy.go @@ -1929,8 +1929,18 @@ 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) + *out = make(map[string][]NetworkPeeringStatus, len(*in)) + for key, val := range *in { + var outVal []NetworkPeeringStatus + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = make([]NetworkPeeringStatus, len(*in)) + copy(*out, *in) + } + (*out)[key] = outVal + } } return } diff --git a/apinetlet/controllers/conversion.go b/apinetlet/controllers/conversion.go index e81516ed..b14c717b 100644 --- a/apinetlet/controllers/conversion.go +++ b/apinetlet/controllers/conversion.go @@ -80,27 +80,32 @@ func apiNetNetworkInterfaceStateToNetworkInterfaceState(state apinetv1alpha1.Net } } -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 { - prefixStatus := []networkingv1alpha1.PeeringPrefixStatus{} - if peering.State == apinetv1alpha1.NetworkPeeringStateReady { - for _, peeringPrefix := range specPeerings[idx].Prefixes { - prefixStatus = append(prefixStatus, networkingv1alpha1.PeeringPrefixStatus{ - Name: peeringPrefix.Name, - Prefix: (*commonv1alpha1.IPPrefix)(peeringPrefix.Prefix), - }) +func apiNetNetworkPeeringsStatusToNetworkPeeringsStatus(partitionPeeringsMap map[string][]apinetv1alpha1.NetworkPeeringStatus, specPeerings []apinetv1alpha1.NetworkPeering) []networkingv1alpha1.NetworkPeeringStatus { + var networkPeeringsStatus []networkingv1alpha1.NetworkPeeringStatus + for _, peerings := range partitionPeeringsMap { + if len(peerings) == 0 { + continue + } + for _, peering := range peerings { + idx := slices.IndexFunc(specPeerings, func(specPeering apinetv1alpha1.NetworkPeering) bool { + return specPeering.ID == strconv.Itoa(int(peering.ID)) + }) + if idx != -1 { + var prefixStatus []networkingv1alpha1.PeeringPrefixStatus + if peering.State == apinetv1alpha1.NetworkPeeringStateReady { + for _, peeringPrefix := range specPeerings[idx].Prefixes { + prefixStatus = append(prefixStatus, networkingv1alpha1.PeeringPrefixStatus{ + Name: peeringPrefix.Name, + Prefix: (*commonv1alpha1.IPPrefix)(peeringPrefix.Prefix), + }) + } } + networkPeeringsStatus = append(networkPeeringsStatus, networkingv1alpha1.NetworkPeeringStatus{ + Name: specPeerings[idx].Name, + State: networkingv1alpha1.NetworkPeeringState(peering.State), + Prefixes: prefixStatus, + }) } - networkPeeringsStatus = append(networkPeeringsStatus, networkingv1alpha1.NetworkPeeringStatus{ - Name: specPeerings[idx].Name, - State: networkingv1alpha1.NetworkPeeringState(peering.State), - Prefixes: prefixStatus, - }) } } return networkPeeringsStatus diff --git a/apinetlet/controllers/network_controller.go b/apinetlet/controllers/network_controller.go index e4d79f46..ad16afe9 100644 --- a/apinetlet/controllers/network_controller.go +++ b/apinetlet/controllers/network_controller.go @@ -6,11 +6,13 @@ package controllers import ( "context" "fmt" + "reflect" "slices" "github.com/go-logr/logr" apinetv1alpha1 "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1" + "github.com/ironcore-dev/ironcore-net/apimachinery/equality" apinetletclient "github.com/ironcore-dev/ironcore-net/apinetlet/client" "github.com/ironcore-dev/ironcore-net/apinetlet/handler" "github.com/ironcore-dev/ironcore-net/apinetlet/provider" @@ -118,12 +120,17 @@ 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, apiNetNetwork *apinetv1alpha1.Network, state networkingv1alpha1.NetworkState) error { +func (r *NetworkReconciler) updateNetworkStatus(ctx context.Context, log logr.Logger, 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) + statusPeerings := apiNetNetworkPeeringsStatusToNetworkPeeringsStatus(apiNetNetwork.Status.Peerings, apiNetNetwork.Spec.Peerings) + log.V(1).Info("network status peerings", "old", network.Status.Peerings, "new", statusPeerings) + if network.Status.State != state || !reflect.DeepEqual(network.Status.Peerings, statusPeerings) { + log.V(1).Info("Patching network status") + network.Status.State = state + network.Status.Peerings = statusPeerings + if err := r.Status().Patch(ctx, network, client.MergeFrom(networkBase)); err != nil { + return fmt.Errorf("unable to patch network: %w", err) + } } return nil } @@ -144,7 +151,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, apiNetNetwork, networkingv1alpha1.NetworkStatePending); err != nil { + if err := r.updateNetworkStatus(ctx, log, network, apiNetNetwork, networkingv1alpha1.NetworkStatePending); err != nil { log.Error(err, "Error updating network state") } } @@ -164,7 +171,7 @@ func (r *NetworkReconciler) reconcile(ctx context.Context, log logr.Logger, netw } log.V(1).Info("Updating network status") - if err := r.updateNetworkStatus(ctx, network, apiNetNetwork, networkingv1alpha1.NetworkStateAvailable); err != nil { + if err := r.updateNetworkStatus(ctx, log, network, apiNetNetwork, networkingv1alpha1.NetworkStateAvailable); err != nil { return ctrl.Result{}, fmt.Errorf("error updating network status: %w", err) } log.V(1).Info("Updated network status") @@ -187,16 +194,29 @@ func (r *NetworkReconciler) setNetworkProviderID( } func (r *NetworkReconciler) applyAPINetNetwork(ctx context.Context, log logr.Logger, network *networkingv1alpha1.Network) (*apinetv1alpha1.Network, error) { - apiNetNetwork := &apinetv1alpha1.Network{ - TypeMeta: metav1.TypeMeta{ - APIVersion: apinetv1alpha1.SchemeGroupVersion.String(), - Kind: "Network", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: r.APINetNamespace, - Name: string(network.UID), - Labels: apinetletclient.SourceLabels(r.Scheme(), r.RESTMapper(), network), - }, + isNetworkExist := false + apiNetNetwork := &apinetv1alpha1.Network{} + apiNetNetworkKey := client.ObjectKey{Namespace: r.APINetNamespace, Name: string(network.UID)} + log.V(1).Info("Check if APINet network already exists") + if err := r.APINetClient.Get(ctx, apiNetNetworkKey, apiNetNetwork); err != nil { + if !apierrors.IsNotFound(err) { + return nil, fmt.Errorf("error getting apinet network %s: %w", apiNetNetworkKey.Name, err) + } else { + apiNetNetwork = &apinetv1alpha1.Network{ + TypeMeta: metav1.TypeMeta{ + APIVersion: apinetv1alpha1.SchemeGroupVersion.String(), + Kind: "Network", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: r.APINetNamespace, + Name: string(network.UID), + Labels: apinetletclient.SourceLabels(r.Scheme(), r.RESTMapper(), network), + }, + } + } + } else { + log.V(1).Info("APINet network already exists") + isNetworkExist = true } var peerings []apinetv1alpha1.NetworkPeering @@ -228,17 +248,25 @@ func (r *NetworkReconciler) applyAPINetNetwork(ctx context.Context, log logr.Log }) } } - 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 { - return nil, fmt.Errorf("error applying APINet network: %w", err) + isPeeringsEqual := equality.Semantic.DeepEqual(apiNetNetwork.Spec.Peerings, peerings) + + if !isNetworkExist || !isPeeringsEqual { + log.V(1).Info("Applying APINet network") + + if !isPeeringsEqual { + apiNetNetwork.Spec.Peerings = peerings + } + apiNetNetwork.ManagedFields = nil + if err := r.APINetClient.Patch(ctx, apiNetNetwork, client.Apply, fieldOwner, client.ForceOwnership); err != nil { + return nil, fmt.Errorf("error applying apinet network: %w", err) + } } return apiNetNetwork, nil } func (r *NetworkReconciler) getAPINetNetworkPeeringPrefixes(ctx context.Context, peeringPrefixes []networkingv1alpha1.PeeringPrefix, networkNamespace string) ([]apinetv1alpha1.PeeringPrefix, error) { - apinetPeeringPrefixes := []apinetv1alpha1.PeeringPrefix{} + var apinetPeeringPrefixes []apinetv1alpha1.PeeringPrefix for _, prefix := range peeringPrefixes { if prefix.Prefix != nil { apinetPeeringPrefixes = append(apinetPeeringPrefixes, apinetv1alpha1.PeeringPrefix{ diff --git a/apinetlet/controllers/network_controller_test.go b/apinetlet/controllers/network_controller_test.go index 3b0cc086..90743b82 100644 --- a/apinetlet/controllers/network_controller_test.go +++ b/apinetlet/controllers/network_controller_test.go @@ -201,7 +201,8 @@ var _ = Describe("NetworkController", func() { By("patching apinet network peering status") apiNetNetwork2ID, _ := strconv.Atoi(apiNetNetwork2.Spec.ID) Eventually(UpdateStatus(apiNetNetwork1, func() { - apiNetNetwork1.Status.Peerings = []apinetv1alpha1.NetworkPeeringStatus{{ + apiNetNetwork1.Status.Peerings = make(map[string][]apinetv1alpha1.NetworkPeeringStatus) + apiNetNetwork1.Status.Peerings["partition1"] = []apinetv1alpha1.NetworkPeeringStatus{{ ID: int32(apiNetNetwork2ID), State: apinetv1alpha1.NetworkPeeringStateReady, }} @@ -209,7 +210,8 @@ var _ = Describe("NetworkController", func() { apiNetNetwork1ID, _ := strconv.Atoi(apiNetNetwork1.Spec.ID) Eventually(UpdateStatus(apiNetNetwork2, func() { - apiNetNetwork2.Status.Peerings = []apinetv1alpha1.NetworkPeeringStatus{{ + apiNetNetwork2.Status.Peerings = make(map[string][]apinetv1alpha1.NetworkPeeringStatus) + apiNetNetwork2.Status.Peerings["partition1"] = []apinetv1alpha1.NetworkPeeringStatus{{ ID: int32(apiNetNetwork1ID), State: apinetv1alpha1.NetworkPeeringStateReady, }} @@ -377,7 +379,8 @@ var _ = Describe("NetworkController", func() { By("patching apinet network peering status") apiNetNetwork2ID, _ := strconv.Atoi(apiNetNetwork2.Spec.ID) Eventually(UpdateStatus(apiNetNetwork1, func() { - apiNetNetwork1.Status.Peerings = []apinetv1alpha1.NetworkPeeringStatus{{ + apiNetNetwork1.Status.Peerings = make(map[string][]apinetv1alpha1.NetworkPeeringStatus) + apiNetNetwork1.Status.Peerings["partition1"] = []apinetv1alpha1.NetworkPeeringStatus{{ ID: int32(apiNetNetwork2ID), State: apinetv1alpha1.NetworkPeeringStateReady, }} @@ -385,7 +388,8 @@ var _ = Describe("NetworkController", func() { apiNetNetwork1ID, _ := strconv.Atoi(apiNetNetwork1.Spec.ID) Eventually(UpdateStatus(apiNetNetwork2, func() { - apiNetNetwork2.Status.Peerings = []apinetv1alpha1.NetworkPeeringStatus{{ + apiNetNetwork2.Status.Peerings = make(map[string][]apinetv1alpha1.NetworkPeeringStatus) + apiNetNetwork2.Status.Peerings["partition1"] = []apinetv1alpha1.NetworkPeeringStatus{{ ID: int32(apiNetNetwork1ID), State: apinetv1alpha1.NetworkPeeringStateReady, }} diff --git a/client-go/applyconfigurations/core/v1alpha1/networkstatus.go b/client-go/applyconfigurations/core/v1alpha1/networkstatus.go index 02623207..8cb0c087 100644 --- a/client-go/applyconfigurations/core/v1alpha1/networkstatus.go +++ b/client-go/applyconfigurations/core/v1alpha1/networkstatus.go @@ -5,10 +5,14 @@ package v1alpha1 +import ( + v1alpha1 "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1" +) + // NetworkStatusApplyConfiguration represents an declarative configuration of the NetworkStatus type for use // with apply. type NetworkStatusApplyConfiguration struct { - Peerings []NetworkPeeringStatusApplyConfiguration `json:"peerings,omitempty"` + Peerings map[string][]v1alpha1.NetworkPeeringStatus `json:"peerings,omitempty"` } // NetworkStatusApplyConfiguration constructs an declarative configuration of the NetworkStatus type for use with @@ -17,15 +21,16 @@ func NetworkStatus() *NetworkStatusApplyConfiguration { return &NetworkStatusApplyConfiguration{} } -// WithPeerings adds the given value to the Peerings field in the declarative configuration +// WithPeerings puts the entries into 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]) +// If called multiple times, the entries provided by each call will be put on the Peerings field, +// overwriting an existing map entries in Peerings field with the same key. +func (b *NetworkStatusApplyConfiguration) WithPeerings(entries map[string][]v1alpha1.NetworkPeeringStatus) *NetworkStatusApplyConfiguration { + if b.Peerings == nil && len(entries) > 0 { + b.Peerings = make(map[string][]v1alpha1.NetworkPeeringStatus, len(entries)) + } + for k, v := range entries { + b.Peerings[k] = v } return b } diff --git a/client-go/applyconfigurations/internal/internal.go b/client-go/applyconfigurations/internal/internal.go index f45ede9e..c56e4dee 100644 --- a/client-go/applyconfigurations/internal/internal.go +++ b/client-go/applyconfigurations/internal/internal.go @@ -972,10 +972,12 @@ var schemaYAML = typed.YAMLObject(`types: fields: - name: peerings type: - list: + map: elementType: - namedType: com.github.ironcore-dev.ironcore-net.api.core.v1alpha1.NetworkPeeringStatus - elementRelationship: atomic + 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/openapi/api_violations.report b/client-go/openapi/api_violations.report index b7c1e0db..2be1b68a 100644 --- a/client-go/openapi/api_violations.report +++ b/client-go/openapi/api_violations.report @@ -29,7 +29,6 @@ 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,NetworkPolicySpec,Ingress API rule violation: list_type_missing,github.com/ironcore-dev/ironcore-net/api/core/v1alpha1,NetworkPolicySpec,PolicyTypes 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 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 4d24c205..24841bdd 100644 --- a/client-go/openapi/zz_generated.openapi.go +++ b/client-go/openapi/zz_generated.openapi.go @@ -3430,12 +3430,20 @@ func schema_ironcore_net_api_core_v1alpha1_NetworkStatus(ref common.ReferenceCal "peerings": { SchemaProps: spec.SchemaProps{ Description: "Peerings contains the states of the network peerings for the network.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/ironcore-dev/ironcore-net/api/core/v1alpha1.NetworkPeeringStatus"), + 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"), + }, + }, + }, }, }, }, diff --git a/docs/api-reference/core.md b/docs/api-reference/core.md index c9a7bc9a..47de3fda 100644 --- a/docs/api-reference/core.md +++ b/docs/api-reference/core.md @@ -1556,7 +1556,7 @@ LocalUIDReference
NetworkRef is the network the load balancer is assigned to.
+NetworkRef is the network to which network policy is applied.
-(Appears on:NetworkStatus) -
NetworkPeeringStatus is the status of a network peering.
peerings
PeeringPrefixes defines prefixes to be exposed to the peered network
+PeeringPrefix defines prefixes to be exposed to the peered network