diff --git a/api/core/v1alpha1/network_types.go b/api/core/v1alpha1/network_types.go index 836f1bd2..6e097188 100644 --- a/api/core/v1alpha1/network_types.go +++ b/api/core/v1alpha1/network_types.go @@ -10,9 +10,45 @@ import ( type NetworkSpec struct { // ID is the ID of the network. ID string `json:"id,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 { + // 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" + // 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 { + // ID is the ID of network + ID int32 `json:"id"` + // 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 94f1e52a..7153a27e 100644 --- a/api/core/v1alpha1/zz_generated.deepcopy.go +++ b/api/core/v1alpha1/zz_generated.deepcopy.go @@ -1176,8 +1176,8 @@ func (in *Network) DeepCopyInto(out *Network) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec - out.Status = in.Status + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) return } @@ -1522,9 +1522,46 @@ 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 + 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 + if in.Peerings != nil { + in, out := &in.Peerings, &out.Peerings + *out = make([]NetworkPeering, len(*in)) + copy(*out, *in) + } return } @@ -1541,6 +1578,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/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 06914801..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,6 +196,27 @@ func (r *NetworkReconciler) applyAPINetNetwork(ctx context.Context, log logr.Log }, } + var peerings []apinetv1alpha1.NetworkPeering + 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 + } + + 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.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) diff --git a/apinetlet/controllers/network_controller_test.go b/apinetlet/controllers/network_controller_test.go index a2cfba6d..f4d0a704 100644 --- a/apinetlet/controllers/network_controller_test.go +++ b/apinetlet/controllers/network_controller_test.go @@ -4,7 +4,9 @@ package controllers import ( - "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1" + "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" networkingv1alpha1 "github.com/ironcore-dev/ironcore/api/networking/v1alpha1" @@ -19,6 +21,7 @@ import ( var _ = Describe("NetworkController", func() { ns := SetupNamespace(&k8sClient) + ns1 := SetupNamespace(&k8sClient) apiNetNs := SetupNamespace(&k8sClient) SetupTest(apiNetNs) @@ -33,7 +36,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 +74,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 +88,161 @@ 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, + 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, + State: networkingv1alpha1.NetworkPeeringStatePending, + }} + Expect(k8sClient.Patch(ctx, network2, client.MergeFrom(baseNetwork2))).To(Succeed()) + + By("ensuring apinet network spec peerings are updated") + Eventually(Object(apiNetNetwork1)).Should(SatisfyAll( + HaveField("Spec.Peerings", ConsistOf(apinetv1alpha1.NetworkPeering{ + Name: network1.Spec.Peerings[0].Name, + ID: apiNetNetwork2.Spec.ID, + })), + )) + + Eventually(Object(apiNetNetwork2)).Should(SatisfyAll( + 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") + 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/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/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 new file mode 100644 index 00000000..68a76fcc --- /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 { + ID *int32 `json:"id,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{} +} + +// 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 *NetworkPeeringStatusApplyConfiguration) WithID(value int32) *NetworkPeeringStatusApplyConfiguration { + b.ID = &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/networkspec.go b/client-go/applyconfigurations/core/v1alpha1/networkspec.go index 3af55c69..b8b350a8 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"` + Peerings []NetworkPeeringApplyConfiguration `json:"peerings,omitempty"` } // NetworkSpecApplyConfiguration constructs an declarative configuration of the NetworkSpec type for use with @@ -24,3 +25,16 @@ func (b *NetworkSpecApplyConfiguration) WithID(value string) *NetworkSpecApplyCo b.ID = &value return b } + +// 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 *NetworkSpecApplyConfiguration) WithPeerings(values ...*NetworkPeeringApplyConfiguration) *NetworkSpecApplyConfiguration { + 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/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 5748facb..27cc8965 100644 --- a/client-go/applyconfigurations/internal/internal.go +++ b/client-go/applyconfigurations/internal/internal.go @@ -766,24 +766,48 @@ var schemaYAML = typed.YAMLObject(`types: - name: state type: scalar: string +- 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 - name: com.github.ironcore-dev.ironcore-net.api.core.v1alpha1.NetworkSpec map: fields: - name: id type: scalar: string + - name: peerings + type: + list: + elementType: + 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: - 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..b04cc99a 100644 --- a/client-go/applyconfigurations/utils.go +++ b/client-go/applyconfigurations/utils.go @@ -106,8 +106,14 @@ 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"): 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 125a08aa..d538a9ce 100644 --- a/client-go/openapi/api_violations.report +++ b/client-go/openapi/api_violations.report @@ -16,6 +16,8 @@ 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,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 2b07a468..f7b84e7d 100644 --- a/client-go/openapi/zz_generated.openapi.go +++ b/client-go/openapi/zz_generated.openapi.go @@ -78,6 +78,8 @@ 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), "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1.Node": schema_ironcore_net_api_core_v1alpha1_Node(ref), @@ -2765,6 +2767,65 @@ func schema_ironcore_net_api_core_v1alpha1_NetworkList(ref common.ReferenceCallb } } +func schema_ironcore_net_api_core_v1alpha1_NetworkPeering(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + 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 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", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"id"}, + }, + }, + } +} + func schema_ironcore_net_api_core_v1alpha1_NetworkSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -2778,9 +2839,25 @@ func schema_ironcore_net_api_core_v1alpha1_NetworkSpec(ref common.ReferenceCallb Format: "", }, }, + "peerings": { + SchemaProps: spec.SchemaProps{ + Description: "Peerings are the network peerings with this 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.NetworkPeering"), + }, + }, + }, + }, + }, }, }, }, + Dependencies: []string{ + "github.com/ironcore-dev/ironcore-net/api/core/v1alpha1.NetworkPeering"}, } } @@ -2789,8 +2866,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/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/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/go.mod b/go.mod index c9f2dd61..036e43a3 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.20240116114543-d37a145029e7 - github.com/ironcore-dev/metalnet v0.3.8 + 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 github.com/spf13/cobra v1.8.0 @@ -90,19 +90,19 @@ 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.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 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-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.0 // 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 9dd7ac62..665d9dfc 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,6 @@ -cloud.google.com/go v0.110.10 h1:LXy9GEO+timppncPIAZoOj3l58LIU9k+kn48AN7IO3Y= -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 v0.112.0 h1:tpFCD7hpHFlQ8yPwT3x+QeXqc2T6+n6T+hmABHfDUSM= +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= @@ -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,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.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/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.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= 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.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0= -golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= +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= @@ -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= @@ -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-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.0 h1:N4fmtePxOZ+bwiK1RhVEztOU+gkoVkvterHgpwAuiTw= -k8s.io/kube-aggregator v0.29.0/go.mod h1:bjatII63ORkFg5yUFP2qm2OC49R0wwxZhRVIyJ4Z4X0= +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 29de3567..cfd999fe 100644 --- a/internal/apis/core/network_types.go +++ b/internal/apis/core/network_types.go @@ -10,9 +10,45 @@ import ( type NetworkSpec struct { // ID is the ID of the network. ID 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 { + // 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" + // 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 { + // ID is the ID of network + ID int32 `json:"id"` + // 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 a59e854f..8b88226c 100644 --- a/internal/apis/core/v1alpha1/zz_generated.conversion.go +++ b/internal/apis/core/v1alpha1/zz_generated.conversion.go @@ -608,6 +608,26 @@ 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 { + 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,8 +2197,53 @@ func Convert_core_NetworkList_To_v1alpha1_NetworkList(in *core.NetworkList, out return autoConvert_core_NetworkList_To_v1alpha1_NetworkList(in, out, s) } +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 +} + +// 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.ID = in.ID + 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.Peerings = *(*[]core.NetworkPeering)(unsafe.Pointer(&in.Peerings)) return nil } @@ -2189,6 +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.Peerings = *(*[]v1alpha1.NetworkPeering)(unsafe.Pointer(&in.Peerings)) return nil } @@ -2198,6 +2264,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 } @@ -2207,6 +2274,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 9c40dbd1..aa967534 100644 --- a/internal/apis/core/zz_generated.deepcopy.go +++ b/internal/apis/core/zz_generated.deepcopy.go @@ -1176,8 +1176,8 @@ func (in *Network) DeepCopyInto(out *Network) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec - out.Status = in.Status + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) return } @@ -1522,9 +1522,46 @@ 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 + 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 + if in.Peerings != nil { + in, out := &in.Peerings, &out.Peerings + *out = make([]NetworkPeering, len(*in)) + copy(*out, *in) + } return } @@ -1541,6 +1578,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/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 2d1d340e..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) @@ -144,11 +154,27 @@ func (r *NetworkReconciler) reconcile(ctx context.Context, log logr.Logger, netw ID: vni, }, } + + 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, 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) } 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 } @@ -156,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 baf8c24d..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,32 +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{}, } - Expect(k8sClient.Create(ctx, network)).To(Succeed()) + Expect(k8sClient.Create(ctx, network1)).To(Succeed()) - By("parsing the VNI") - vni, err := networkid.ParseVNI(network.Spec.ID) + By("creating a apinet network-2") + network2 := &apinetv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns.Name, + Name: "network-2", + }, + } + 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("waiting for the metalnet network to be created") - metalnetNetwork := &metalnetv1alpha1.Network{ + By("parsing the VNI of network-2") + network2Vni, err := networkid.ParseVNI(network2.Spec.ID) + Expect(err).NotTo(HaveOccurred()) + + By("waiting for the metalnet networks to be created") + metalnetNetwork1 := &metalnetv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: metalnetNs.Name, + Name: string(network1.UID), + }, + } + Eventually(Object(metalnetNetwork1)).Should(SatisfyAll( + HaveField("Spec", metalnetv1alpha1.NetworkSpec{ + ID: network1Vni, + PeeredIDs: []int32{network2Vni}, + }), + )) + + metalnetNetwork2 := &metalnetv1alpha1.Network{ ObjectMeta: metav1.ObjectMeta{ Namespace: metalnetNs.Name, - Name: string(network.UID), + Name: string(network2.UID), }, } - Eventually(Object(metalnetNetwork)).Should(SatisfyAll( + Eventually(Object(metalnetNetwork2)).Should(SatisfyAll( HaveField("Spec", metalnetv1alpha1.NetworkSpec{ - ID: vni, + 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)) + }) })