Files
netbird-kubernetes-operator/internal/controller/tcproute_controller.go
T

176 lines
5.1 KiB
Go
Raw Normal View History

2026-03-23 09:59:48 +01:00
package controller
import (
"context"
2026-04-30 13:39:11 +02:00
"github.com/fluxcd/pkg/runtime/patch"
2026-03-23 09:59:48 +01:00
corev1 "k8s.io/api/core/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
2026-04-30 13:39:11 +02:00
gwv1 "sigs.k8s.io/gateway-api/apis/v1"
gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
2026-03-23 09:59:48 +01:00
nbv1alpha1 "github.com/netbirdio/kubernetes-operator/api/v1alpha1"
2026-03-23 09:59:48 +01:00
"github.com/netbirdio/kubernetes-operator/internal/gatewayutil"
2026-04-23 19:18:06 +02:00
"github.com/netbirdio/kubernetes-operator/internal/k8sutil"
nbv1alpha1ac "github.com/netbirdio/kubernetes-operator/pkg/applyconfigurations/api/v1alpha1"
2026-03-23 09:59:48 +01:00
)
type TCPRouteReconciler struct {
client.Client
}
// nolint:gocyclo
func (r *TCPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
logger := ctrl.Log.WithName("TCPRoute").WithValues("namespace", req.Namespace, "name", req.Name)
2026-04-30 13:39:11 +02:00
tr := &gwv1alpha2.TCPRoute{}
err := r.Get(ctx, req.NamespacedName, tr)
2026-03-23 09:59:48 +01:00
if err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}
sp := patch.NewSerialPatcher(tr, r.Client)
2026-03-23 09:59:48 +01:00
if !tr.DeletionTimestamp.IsZero() {
return r.reconcileDelete(ctx, sp, tr)
2026-03-23 09:59:48 +01:00
}
for _, parent := range tr.Spec.ParentRefs {
gw, err := gatewayutil.GetParentGateway(ctx, r.Client, parent, tr.Namespace, GatewayControllerName)
if err != nil {
return ctrl.Result{}, err
}
if gw == nil {
continue
}
2026-04-30 13:39:11 +02:00
if !meta.IsStatusConditionTrue(gw.Status.Conditions, string(gwv1.GatewayConditionProgrammed)) {
2026-03-23 09:59:48 +01:00
logger.Info("gateway is not ready", "name", gw.ObjectMeta.Name)
continue
}
netRouter, err := gatewayutil.GetGatewayNetworkRouter(ctx, r.Client, gw)
2026-03-23 09:59:48 +01:00
if err != nil {
return ctrl.Result{}, err
}
2026-04-23 19:18:06 +02:00
controllerutil.AddFinalizer(tr, k8sutil.Finalizer("tcproute"))
err = sp.Patch(ctx, tr)
if err != nil {
return ctrl.Result{}, err
2026-03-23 09:59:48 +01:00
}
// Create network resources.
svcIdx := map[string]corev1.Service{}
for _, rule := range tr.Spec.Rules {
for _, ref := range rule.BackendRefs {
key := client.ObjectKey{Namespace: tr.Namespace, Name: string(ref.Name)}
var svc corev1.Service
err := r.Client.Get(ctx, key, &svc)
if err != nil {
return ctrl.Result{}, err
}
svcIdx[svc.Name] = svc
}
}
for _, svc := range svcIdx {
2026-04-23 19:18:06 +02:00
controllerRef, err := k8sutil.ControllerReference(&svc, r.Scheme())
if err != nil {
return ctrl.Result{}, err
2026-03-23 09:59:48 +01:00
}
controllerRef = controllerRef.WithBlockOwnerDeletion(false)
2026-04-23 19:18:06 +02:00
ownerRef, err := k8sutil.OwnerReference(tr, r.Scheme())
if err != nil {
return ctrl.Result{}, err
}
netResourceAC := nbv1alpha1ac.NetworkResource(svc.Name, svc.Namespace).
WithOwnerReferences(controllerRef, ownerRef).
WithSpec(
nbv1alpha1ac.NetworkResourceSpec().
WithNetworkRouterRef(nbv1alpha1ac.CrossNamespaceReference().WithName(netRouter.Name).WithNamespace(netRouter.Namespace)).
WithServiceRef(corev1.LocalObjectReference{Name: svc.Name}),
)
err = r.Client.Apply(ctx, netResourceAC)
2026-03-23 09:59:48 +01:00
if err != nil {
return ctrl.Result{}, err
}
}
}
return ctrl.Result{}, nil
}
2026-04-30 13:39:11 +02:00
func (r *TCPRouteReconciler) reconcileDelete(ctx context.Context, sp *patch.SerialPatcher, tr *gwv1alpha2.TCPRoute) (ctrl.Result, error) {
2026-03-23 09:59:48 +01:00
for _, parent := range tr.Spec.ParentRefs {
gw, err := gatewayutil.GetParentGateway(ctx, r.Client, parent, tr.Namespace, GatewayControllerName)
if err != nil {
return ctrl.Result{}, err
}
if gw == nil {
continue
}
// Remove the resource from the resource.
svcIdx := map[string]corev1.Service{}
for _, rule := range tr.Spec.Rules {
for _, ref := range rule.BackendRefs {
key := client.ObjectKey{Namespace: tr.Namespace, Name: string(ref.Name)}
var svc corev1.Service
err := r.Client.Get(ctx, key, &svc)
if kerrors.IsNotFound(err) {
continue
}
if err != nil {
return ctrl.Result{}, err
}
svcIdx[svc.Name] = svc
}
}
for _, svc := range svcIdx {
netResource := &nbv1alpha1.NetworkResource{
ObjectMeta: metav1.ObjectMeta{
Name: svc.Name,
Namespace: svc.Namespace,
},
}
err = r.Client.Get(ctx, client.ObjectKeyFromObject(netResource), netResource)
2026-03-23 09:59:48 +01:00
if err != nil {
return ctrl.Result{}, err
}
err = controllerutil.RemoveOwnerReference(tr, netResource, r.Scheme())
2026-03-23 09:59:48 +01:00
if err != nil {
return ctrl.Result{}, err
}
if len(netResource.OwnerReferences) > 1 {
err = r.Client.Update(ctx, netResource)
2026-03-23 09:59:48 +01:00
if err != nil {
return ctrl.Result{}, err
}
} else {
// TODO: Precondition that nothing has changed.
err := r.Client.Delete(ctx, netResource)
2026-03-23 09:59:48 +01:00
if err != nil {
return ctrl.Result{}, err
}
}
}
}
2026-04-23 19:18:06 +02:00
controllerutil.RemoveFinalizer(tr, k8sutil.Finalizer("tcproute"))
err := sp.Patch(ctx, tr)
if err != nil {
return ctrl.Result{}, err
2026-03-23 09:59:48 +01:00
}
return ctrl.Result{}, nil
}
// SetupWithManager sets up the controller with the Manager.
func (r *TCPRouteReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
2026-04-30 13:39:11 +02:00
For(&gwv1alpha2.TCPRoute{}).
2026-03-23 09:59:48 +01:00
Complete(r)
}