Update Gateway API to use new resources (#201)

We dont want to promote the use of the "old" resources with NB prefix so
the Gateway API integration should only support the new ones.

---------

Signed-off-by: Philip Laine <philip.laine@gmail.com>
This commit is contained in:
Philip Laine
2026-04-23 16:11:15 +02:00
committed by GitHub
parent 99ef70603f
commit 876a0e1eb3
10 changed files with 209 additions and 219 deletions
-2
View File
@@ -334,14 +334,12 @@ func main() {
if err = (&controller.HTTPRouteReconciler{ if err = (&controller.HTTPRouteReconciler{
Client: mgr.GetClient(), Client: mgr.GetClient(),
Netbird: nbClient, Netbird: nbClient,
ClusterDNS: clusterDNS,
}).SetupWithManager(mgr); err != nil { }).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "HTTPRoute") setupLog.Error(err, "unable to create controller", "controller", "HTTPRoute")
os.Exit(1) os.Exit(1)
} }
if err = (&controller.TCPRouteReconciler{ if err = (&controller.TCPRouteReconciler{
Client: mgr.GetClient(), Client: mgr.GetClient(),
ClusterDNS: clusterDNS,
}).SetupWithManager(mgr); err != nil { }).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "TCPRoute") setupLog.Error(err, "unable to create controller", "controller", "TCPRoute")
os.Exit(1) os.Exit(1)
+21 -5
View File
@@ -1,9 +1,25 @@
apiVersion: netbird.io/v1 apiVersion: netbird.io/v1alpha1
kind: NBRoutingPeer kind: NetworkRouter
metadata: metadata:
name: netbird name: netbird
namespace: netbird namespace: netbird
spec: {} spec:
dnsZoneRef:
name: cluster.local
---
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: netbird-public
spec:
controllerName: "gateway.netbird.io/controller"
---
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: netbird-private
spec:
controllerName: "gateway.netbird.io/controller"
--- ---
apiVersion: gateway.networking.k8s.io/v1 apiVersion: gateway.networking.k8s.io/v1
kind: Gateway kind: Gateway
@@ -13,7 +29,7 @@ metadata:
spec: spec:
gatewayClassName: netbird-private gatewayClassName: netbird-private
listeners: listeners:
- protocol: gateway.netbird.io/NBRoutingPeer - protocol: gateway.netbird.io/NetworkRouter
name: netbird name: netbird
port: 1 port: 1
--- ---
@@ -25,6 +41,6 @@ metadata:
spec: spec:
gatewayClassName: netbird-public gatewayClassName: netbird-public
listeners: listeners:
- protocol: gateway.netbird.io/NBRoutingPeer - protocol: gateway.netbird.io/NetworkRouter
name: netbird name: netbird
port: 1 port: 1
+24 -47
View File
@@ -19,11 +19,10 @@ package controller
import ( import (
"context" "context"
"fmt" "fmt"
"slices"
"time" "time"
netbird "github.com/netbirdio/netbird/shared/management/client/rest" "github.com/fluxcd/pkg/runtime/conditions"
corev1 "k8s.io/api/core/v1" "github.com/fluxcd/pkg/runtime/patch"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
@@ -32,24 +31,21 @@ import (
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1" nbv1alpha1 "github.com/netbirdio/kubernetes-operator/api/v1alpha1"
"github.com/netbirdio/kubernetes-operator/internal/gatewayutil" "github.com/netbirdio/kubernetes-operator/internal/gatewayutil"
) )
const (
GatewayFinalizer = "gateway.netbird.io/gateway"
)
type GatewayReconciler struct { type GatewayReconciler struct {
client.Client client.Client
} }
func (r *GatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { func (r *GatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
gw := gatewayv1.Gateway{} gw := &gatewayv1.Gateway{}
err := r.Get(ctx, req.NamespacedName, &gw) err := r.Get(ctx, req.NamespacedName, gw)
if err != nil { if err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err) return ctrl.Result{}, client.IgnoreNotFound(err)
} }
sp := patch.NewSerialPatcher(gw, r.Client)
// Check if referenced class belongs to this controller. // Check if referenced class belongs to this controller.
gwc := &gatewayv1.GatewayClass{} gwc := &gatewayv1.GatewayClass{}
@@ -69,11 +65,11 @@ func (r *GatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
// Handle resource deletion. // Handle resource deletion.
if !gw.DeletionTimestamp.IsZero() { if !gw.DeletionTimestamp.IsZero() {
return r.reconcileDelete(ctx, gw) return r.reconcileDelete(ctx, sp, gw)
} }
// Verify Gateway configuration. // Verify Gateway configuration.
routingPeerName, err := gatewayutil.GetRoutingPeerName(gw.Spec.Listeners) routingPeerName, err := gatewayutil.GetNetworkRouterName(gw.Spec.Listeners)
if err != nil { if err != nil {
cond := metav1.Condition{ cond := metav1.Condition{
Type: string(gatewayv1.GatewayConditionAccepted), Type: string(gatewayv1.GatewayConditionAccepted),
@@ -81,57 +77,43 @@ func (r *GatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
Reason: string(gatewayv1.GatewayReasonInvalidParameters), Reason: string(gatewayv1.GatewayReasonInvalidParameters),
Message: err.Error(), Message: err.Error(),
} }
if meta.SetStatusCondition(&gw.Status.Conditions, cond) { meta.SetStatusCondition(&gw.Status.Conditions, cond)
err = r.Status().Update(ctx, &gw) err = sp.Patch(ctx, gw)
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
}
return ctrl.Result{}, nil return ctrl.Result{}, nil
} }
cond := metav1.Condition{ cond := metav1.Condition{
Type: string(gatewayv1.GatewayConditionAccepted), Type: string(gatewayv1.GatewayConditionAccepted),
Status: metav1.ConditionTrue, Status: metav1.ConditionTrue,
Reason: string(gatewayv1.GatewayReasonAccepted), Reason: string(gatewayv1.GatewayReasonAccepted),
} }
if meta.SetStatusCondition(&gw.Status.Conditions, cond) { meta.SetStatusCondition(&gw.Status.Conditions, cond)
err = r.Status().Update(ctx, &gw) controllerutil.AddFinalizer(gw, nbv1alpha1.NetbirdFinalizer)
err = sp.Patch(ctx, gw)
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
return ctrl.Result{}, nil
}
if controllerutil.AddFinalizer(&gw, GatewayFinalizer) {
err = r.Client.Update(ctx, &gw)
if err != nil {
return ctrl.Result{}, err
}
}
// Ensure routing peer is ready. // Ensure routing peer is ready.
// TODO (phillebaba): Should watch routing peer instead of retrying when not found. netRouter, err := gatewayutil.GetGatewayNetworkRouter(ctx, r.Client, gw)
nbrp, err := gatewayutil.GetGatewayRoutingPeer(ctx, r.Client, gw)
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
idx := slices.IndexFunc(nbrp.Status.Conditions, func(cond netbirdiov1.NBCondition) bool { if !conditions.Has(netRouter, nbv1alpha1.ReadyCondition) {
return cond.Type == netbirdiov1.NBSetupKeyReady // TODO (phillebaba): Should watch routing peer instead of retrying when not found.
})
if idx == -1 || nbrp.Status.Conditions[idx].Status != corev1.ConditionStatus(metav1.ConditionTrue) {
cond := metav1.Condition{ cond := metav1.Condition{
Type: string(gatewayv1.GatewayConditionProgrammed), Type: string(gatewayv1.GatewayConditionProgrammed),
Status: metav1.ConditionFalse, Status: metav1.ConditionFalse,
Reason: string(gatewayv1.GatewayReasonProgrammed), Reason: string(gatewayv1.GatewayReasonProgrammed),
Message: fmt.Sprintf("NBRoutingPeer %s is not ready", routingPeerName), Message: fmt.Sprintf("NBRoutingPeer %s is not ready", routingPeerName),
} }
if meta.SetStatusCondition(&gw.Status.Conditions, cond) { meta.SetStatusCondition(&gw.Status.Conditions, cond)
err = r.Status().Update(ctx, &gw) err = sp.Patch(ctx, gw)
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
return ctrl.Result{}, nil
}
return ctrl.Result{RequeueAfter: 5 * time.Second}, nil return ctrl.Result{RequeueAfter: 5 * time.Second}, nil
} }
@@ -141,18 +123,15 @@ func (r *GatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
Status: metav1.ConditionTrue, Status: metav1.ConditionTrue,
Reason: string(gatewayv1.GatewayReasonProgrammed), Reason: string(gatewayv1.GatewayReasonProgrammed),
} }
if meta.SetStatusCondition(&gw.Status.Conditions, cond) { meta.SetStatusCondition(&gw.Status.Conditions, cond)
err = r.Status().Update(ctx, &gw) err = sp.Patch(ctx, gw)
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
return ctrl.Result{}, nil return ctrl.Result{}, nil
} }
return ctrl.Result{}, nil func (r *GatewayReconciler) reconcileDelete(ctx context.Context, sp *patch.SerialPatcher, gw *gatewayv1.Gateway) (ctrl.Result, error) {
}
func (r *GatewayReconciler) reconcileDelete(ctx context.Context, gw gatewayv1.Gateway) (ctrl.Result, error) {
var httpRouteList gatewayv1.HTTPRouteList var httpRouteList gatewayv1.HTTPRouteList
err := r.Client.List(ctx, &httpRouteList) err := r.Client.List(ctx, &httpRouteList)
if err != nil { if err != nil {
@@ -179,16 +158,14 @@ func (r *GatewayReconciler) reconcileDelete(ctx context.Context, gw gatewayv1.Ga
} }
} }
if controllerutil.RemoveFinalizer(&gw, GatewayFinalizer) { controllerutil.RemoveFinalizer(gw, nbv1alpha1.NetbirdFinalizer)
err := r.Client.Update(ctx, &gw) err = sp.Patch(ctx, gw)
if err != nil && !netbird.IsNotFound(err) { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
}
return ctrl.Result{}, nil return ctrl.Result{}, nil
} }
// SetupWithManager sets up the controller with the Manager.
func (r *GatewayReconciler) SetupWithManager(mgr ctrl.Manager) error { func (r *GatewayReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr). return ctrl.NewControllerManagedBy(mgr).
For(&gatewayv1.Gateway{}). For(&gatewayv1.Gateway{}).
+14 -21
View File
@@ -4,6 +4,8 @@ import (
"context" "context"
"time" "time"
"github.com/fluxcd/pkg/runtime/patch"
nbv1alpha1 "github.com/netbirdio/kubernetes-operator/api/v1alpha1"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
ctrl "sigs.k8s.io/controller-runtime" ctrl "sigs.k8s.io/controller-runtime"
@@ -13,7 +15,6 @@ import (
) )
const ( const (
GatewayClassFinalizer = "gateway.netbird.io/gatewayclass"
GatewayControllerName = "gateway.netbird.io/controller" GatewayControllerName = "gateway.netbird.io/controller"
) )
@@ -22,11 +23,12 @@ type GatewayClassReconciler struct {
} }
func (r *GatewayClassReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { func (r *GatewayClassReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
gwc := gatewayv1.GatewayClass{} gwc := &gatewayv1.GatewayClass{}
err := r.Client.Get(ctx, req.NamespacedName, &gwc) err := r.Client.Get(ctx, req.NamespacedName, gwc)
if err != nil { if err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err) return ctrl.Result{}, client.IgnoreNotFound(err)
} }
sp := patch.NewSerialPatcher(gwc, r.Client)
// Controller name does not match. // Controller name does not match.
if gwc.Spec.ControllerName != GatewayControllerName { if gwc.Spec.ControllerName != GatewayControllerName {
@@ -35,7 +37,7 @@ func (r *GatewayClassReconciler) Reconcile(ctx context.Context, req ctrl.Request
// Gateway class is being deleted. // Gateway class is being deleted.
if !gwc.GetDeletionTimestamp().IsZero() { if !gwc.GetDeletionTimestamp().IsZero() {
return r.reconcileDelete(ctx, gwc) return r.reconcileDelete(ctx, sp, gwc)
} }
// Validate configuration. // Validate configuration.
@@ -55,24 +57,16 @@ func (r *GatewayClassReconciler) Reconcile(ctx context.Context, req ctrl.Request
Reason: string(gatewayv1.GatewayClassReasonInvalidParameters), Reason: string(gatewayv1.GatewayClassReasonInvalidParameters),
Message: message, Message: message,
} }
if meta.SetStatusCondition(&gwc.Status.Conditions, cond) { meta.SetStatusCondition(&gwc.Status.Conditions, cond)
err = r.Client.Status().Update(ctx, &gwc) err := sp.Patch(ctx, gwc)
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
return ctrl.Result{}, nil return ctrl.Result{}, nil
} }
}
// Add finalizer to validate deletion.
if controllerutil.AddFinalizer(&gwc, GatewayClassFinalizer) {
err = r.Client.Update(ctx, &gwc)
if err != nil {
return ctrl.Result{}, err
}
}
// Set condition to accepted. // Set condition to accepted.
controllerutil.AddFinalizer(gwc, nbv1alpha1.NetbirdFinalizer)
cond := metav1.Condition{ cond := metav1.Condition{
Type: string(gatewayv1.GatewayClassConditionStatusAccepted), Type: string(gatewayv1.GatewayClassConditionStatusAccepted),
Status: metav1.ConditionTrue, Status: metav1.ConditionTrue,
@@ -80,15 +74,14 @@ func (r *GatewayClassReconciler) Reconcile(ctx context.Context, req ctrl.Request
Message: "Reconciled by Netbird Operator.", Message: "Reconciled by Netbird Operator.",
} }
meta.SetStatusCondition(&gwc.Status.Conditions, cond) meta.SetStatusCondition(&gwc.Status.Conditions, cond)
err = r.Client.Status().Update(ctx, &gwc) err = sp.Patch(ctx, gwc)
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
return ctrl.Result{}, nil return ctrl.Result{}, nil
} }
func (r *GatewayClassReconciler) reconcileDelete(ctx context.Context, gwc gatewayv1.GatewayClass) (ctrl.Result, error) { func (r *GatewayClassReconciler) reconcileDelete(ctx context.Context, sp *patch.SerialPatcher, gwc *gatewayv1.GatewayClass) (ctrl.Result, error) {
var gatewayList gatewayv1.GatewayList var gatewayList gatewayv1.GatewayList
err := r.Client.List(ctx, &gatewayList) err := r.Client.List(ctx, &gatewayList)
if err != nil { if err != nil {
@@ -99,12 +92,12 @@ func (r *GatewayClassReconciler) reconcileDelete(ctx context.Context, gwc gatewa
return ctrl.Result{RequeueAfter: 5 * time.Second}, nil return ctrl.Result{RequeueAfter: 5 * time.Second}, nil
} }
} }
if controllerutil.RemoveFinalizer(&gwc, GatewayClassFinalizer) {
err = r.Client.Update(ctx, &gwc) controllerutil.RemoveFinalizer(gwc, nbv1alpha1.NetbirdFinalizer)
err = sp.Patch(ctx, gwc)
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
}
return ctrl.Result{}, nil return ctrl.Result{}, nil
} }
+52 -54
View File
@@ -2,9 +2,10 @@ package controller
import ( import (
"context" "context"
"fmt"
"time" "time"
"github.com/fluxcd/pkg/runtime/conditions"
"github.com/fluxcd/pkg/runtime/patch"
netbird "github.com/netbirdio/netbird/shared/management/client/rest" netbird "github.com/netbirdio/netbird/shared/management/client/rest"
"github.com/netbirdio/netbird/shared/management/http/api" "github.com/netbirdio/netbird/shared/management/http/api"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
@@ -16,9 +17,11 @@ import (
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1" nbv1alpha1 "github.com/netbirdio/kubernetes-operator/api/v1alpha1"
"github.com/netbirdio/kubernetes-operator/internal/gatewayutil" "github.com/netbirdio/kubernetes-operator/internal/gatewayutil"
"github.com/netbirdio/kubernetes-operator/internal/ssautil"
"github.com/netbirdio/kubernetes-operator/internal/util" "github.com/netbirdio/kubernetes-operator/internal/util"
nbv1alpha1ac "github.com/netbirdio/kubernetes-operator/pkg/applyconfigurations/api/v1alpha1"
) )
const ( const (
@@ -29,21 +32,21 @@ type HTTPRouteReconciler struct {
client.Client client.Client
Netbird *netbird.Client Netbird *netbird.Client
ClusterDNS string
} }
// nolint:gocyclo // nolint:gocyclo
func (r *HTTPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { func (r *HTTPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
logger := ctrl.Log.WithName("HTTPRoute").WithValues("namespace", req.Namespace, "name", req.Name) logger := ctrl.Log.WithName("HTTPRoute").WithValues("namespace", req.Namespace, "name", req.Name)
hr := gatewayv1.HTTPRoute{} hr := &gatewayv1.HTTPRoute{}
err := r.Get(ctx, req.NamespacedName, &hr) err := r.Get(ctx, req.NamespacedName, hr)
if err != nil { if err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err) return ctrl.Result{}, client.IgnoreNotFound(err)
} }
sp := patch.NewSerialPatcher(hr, r.Client)
if !hr.DeletionTimestamp.IsZero() { if !hr.DeletionTimestamp.IsZero() {
return r.reconcileDelete(ctx, hr) return r.reconcileDelete(ctx, sp, hr)
} }
for _, parent := range hr.Spec.ParentRefs { for _, parent := range hr.Spec.ParentRefs {
@@ -58,17 +61,16 @@ func (r *HTTPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
logger.Info("gateway is not ready", "name", gw.ObjectMeta.Name) logger.Info("gateway is not ready", "name", gw.ObjectMeta.Name)
continue continue
} }
nbrp, err := gatewayutil.GetGatewayRoutingPeer(ctx, r.Client, *gw) netRouter, err := gatewayutil.GetGatewayNetworkRouter(ctx, r.Client, gw)
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
if controllerutil.AddFinalizer(&hr, HTTPRouteFinalizer) { controllerutil.AddFinalizer(hr, nbv1alpha1.NetbirdFinalizer)
err = r.Client.Update(ctx, &hr) err = sp.Patch(ctx, hr)
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
}
// Create network resources. // Create network resources.
svcIdx := map[string]corev1.Service{} svcIdx := map[string]corev1.Service{}
@@ -85,29 +87,23 @@ func (r *HTTPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
} }
for _, svc := range svcIdx { for _, svc := range svcIdx {
nbResource := netbirdiov1.NBResource{ controllerRef, err := ssautil.ControllerReference(&svc, r.Scheme())
ObjectMeta: metav1.ObjectMeta{
Name: svc.Name,
Namespace: svc.Namespace,
},
}
_, err := controllerutil.CreateOrUpdate(ctx, r.Client, &nbResource, func() error {
err = controllerutil.SetControllerReference(&svc, &nbResource, r.Scheme(), controllerutil.WithBlockOwnerDeletion(false))
if err != nil { if err != nil {
return err return ctrl.Result{}, err
} }
err = controllerutil.SetOwnerReference(&hr, &nbResource, r.Scheme()) controllerRef = controllerRef.WithBlockOwnerDeletion(false)
ownerRef, err := ssautil.OwnerReference(hr, r.Scheme())
if err != nil { if err != nil {
return err return ctrl.Result{}, err
} }
nbResource.Spec = netbirdiov1.NBResourceSpec{ netResourceAC := nbv1alpha1ac.NetworkResource(svc.Name, svc.Namespace).
Name: svc.Name, WithOwnerReferences(controllerRef, ownerRef).
NetworkID: *nbrp.Status.NetworkID, WithSpec(
Address: fmt.Sprintf("%s.%s.%s", svc.Name, svc.Namespace, r.ClusterDNS), nbv1alpha1ac.NetworkResourceSpec().
Groups: []string{}, WithNetworkRouterRef(nbv1alpha1ac.CrossNamespaceReference().WithName(netRouter.Name).WithNamespace(netRouter.Namespace)).
} WithServiceRef(corev1.LocalObjectReference{Name: svc.Name}),
return nil )
}) err = r.Client.Apply(ctx, netResourceAC)
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
@@ -115,29 +111,26 @@ func (r *HTTPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
targets := []api.ServiceTarget{} targets := []api.ServiceTarget{}
for _, svc := range svcIdx { for _, svc := range svcIdx {
var nbResource netbirdiov1.NBResource netResource := &nbv1alpha1.NetworkResource{
err := r.Client.Get(ctx, client.ObjectKeyFromObject(&svc), &nbResource) ObjectMeta: metav1.ObjectMeta{
Name: svc.Name,
Namespace: svc.Namespace,
},
}
err := r.Client.Get(ctx, client.ObjectKeyFromObject(netResource), netResource)
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
ready := func() bool { if !conditions.Has(netResource, nbv1alpha1.ReadyCondition) {
for _, cond := range nbResource.Status.Conditions {
if cond.Type == netbirdiov1.NBSetupKeyReady && cond.Status == corev1.ConditionTrue {
return true
}
}
return false
}()
if !ready {
return ctrl.Result{RequeueAfter: 1 * time.Second}, nil return ctrl.Result{RequeueAfter: 1 * time.Second}, nil
} }
target := api.ServiceTarget{ target := api.ServiceTarget{
Enabled: true, Enabled: true,
Path: nil, Path: nil,
TargetId: *nbResource.Status.NetworkResourceID, TargetId: netResource.Status.ResourceID,
Protocol: "http", Protocol: api.ServiceTargetProtocolHttp,
TargetType: "domain", TargetType: api.ServiceTargetTargetTypeHost,
} }
targets = append(targets, target) targets = append(targets, target)
} }
@@ -148,10 +141,11 @@ func (r *HTTPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
return ctrl.Result{}, err return ctrl.Result{}, err
} }
for _, hostname := range hr.Spec.Hostnames { for _, hostname := range hr.Spec.Hostnames {
proxyReq := api.PostApiReverseProxiesServicesJSONRequestBody{ proxyReq := api.ServiceRequest{
Domain: string(hostname), Domain: string(hostname),
Enabled: true, Enabled: true,
Name: string(hostname), Name: string(hostname),
Mode: util.Ptr(api.ServiceRequestModeHttp),
PassHostHeader: util.Ptr(false), PassHostHeader: util.Ptr(false),
RewriteRedirects: util.Ptr(false), RewriteRedirects: util.Ptr(false),
Targets: &targets, Targets: &targets,
@@ -182,7 +176,7 @@ func (r *HTTPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
return ctrl.Result{}, nil return ctrl.Result{}, nil
} }
func (r *HTTPRouteReconciler) reconcileDelete(ctx context.Context, hr gatewayv1.HTTPRoute) (ctrl.Result, error) { func (r *HTTPRouteReconciler) reconcileDelete(ctx context.Context, sp *patch.SerialPatcher, hr *gatewayv1.HTTPRoute) (ctrl.Result, error) {
// Index all proxy services. // Index all proxy services.
proxyServices, err := r.Netbird.ReverseProxyServices.List(ctx) proxyServices, err := r.Netbird.ReverseProxyServices.List(ctx)
if err != nil { if err != nil {
@@ -219,24 +213,29 @@ func (r *HTTPRouteReconciler) reconcileDelete(ctx context.Context, hr gatewayv1.
} }
} }
for _, svc := range svcIdx { for _, svc := range svcIdx {
var nbResource netbirdiov1.NBResource netResource := &nbv1alpha1.NetworkResource{
err = r.Client.Get(ctx, client.ObjectKeyFromObject(&svc), &nbResource) ObjectMeta: metav1.ObjectMeta{
Name: svc.Name,
Namespace: svc.Namespace,
},
}
err = r.Client.Get(ctx, client.ObjectKeyFromObject(netResource), netResource)
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
err = controllerutil.RemoveOwnerReference(&hr, &nbResource, r.Scheme()) err = controllerutil.RemoveOwnerReference(hr, netResource, r.Scheme())
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
if len(nbResource.OwnerReferences) > 1 { if len(netResource.OwnerReferences) > 1 {
err = r.Client.Update(ctx, &nbResource) err = r.Client.Update(ctx, netResource)
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
} else { } else {
// TODO: Precondition that nothing has changed. // TODO: Precondition that nothing has changed.
err := r.Client.Delete(ctx, &nbResource) err := r.Client.Delete(ctx, netResource)
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
@@ -256,12 +255,11 @@ func (r *HTTPRouteReconciler) reconcileDelete(ctx context.Context, hr gatewayv1.
} }
} }
if controllerutil.RemoveFinalizer(&hr, HTTPRouteFinalizer) { controllerutil.RemoveFinalizer(hr, nbv1alpha1.NetbirdFinalizer)
err := r.Client.Update(ctx, &hr) err = sp.Patch(ctx, hr)
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
}
return ctrl.Result{}, nil return ctrl.Result{}, nil
} }
@@ -55,7 +55,7 @@ func (r *NetworkRouterReconciler) Reconcile(ctx context.Context, req ctrl.Reques
return r.reconcileDelete(ctx, sp, netRouter) return r.reconcileDelete(ctx, sp, netRouter)
} }
ownerRef, err := ssautil.OwnerReference(netRouter, r.Scheme()) ownerRef, err := ssautil.ControllerReference(netRouter, r.Scheme())
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
+1 -1
View File
@@ -41,7 +41,7 @@ func (r *SetupKeyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
if err != nil { if err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err) return ctrl.Result{}, client.IgnoreNotFound(err)
} }
owner, err := ssautil.OwnerReference(setupKey, r.Client.Scheme()) owner, err := ssautil.ControllerReference(setupKey, r.Client.Scheme())
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
+38 -44
View File
@@ -2,7 +2,6 @@ package controller
import ( import (
"context" "context"
"fmt"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors" kerrors "k8s.io/apimachinery/pkg/api/errors"
@@ -14,32 +13,30 @@ import (
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1" "github.com/fluxcd/pkg/runtime/patch"
nbv1alpha1 "github.com/netbirdio/kubernetes-operator/api/v1alpha1"
"github.com/netbirdio/kubernetes-operator/internal/gatewayutil" "github.com/netbirdio/kubernetes-operator/internal/gatewayutil"
) "github.com/netbirdio/kubernetes-operator/internal/ssautil"
nbv1alpha1ac "github.com/netbirdio/kubernetes-operator/pkg/applyconfigurations/api/v1alpha1"
const (
TCPRouteFinalizer = "gateway.netbird.io/tcproute"
) )
type TCPRouteReconciler struct { type TCPRouteReconciler struct {
client.Client client.Client
ClusterDNS string
} }
// nolint:gocyclo // nolint:gocyclo
func (r *TCPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { 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) logger := ctrl.Log.WithName("TCPRoute").WithValues("namespace", req.Namespace, "name", req.Name)
tr := gatewayv1alpha2.TCPRoute{} tr := &gatewayv1alpha2.TCPRoute{}
err := r.Get(ctx, req.NamespacedName, &tr) err := r.Get(ctx, req.NamespacedName, tr)
if err != nil { if err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err) return ctrl.Result{}, client.IgnoreNotFound(err)
} }
sp := patch.NewSerialPatcher(tr, r.Client)
if !tr.DeletionTimestamp.IsZero() { if !tr.DeletionTimestamp.IsZero() {
return r.reconcileDelete(ctx, tr) return r.reconcileDelete(ctx, sp, tr)
} }
for _, parent := range tr.Spec.ParentRefs { for _, parent := range tr.Spec.ParentRefs {
@@ -54,17 +51,16 @@ func (r *TCPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
logger.Info("gateway is not ready", "name", gw.ObjectMeta.Name) logger.Info("gateway is not ready", "name", gw.ObjectMeta.Name)
continue continue
} }
nbrp, err := gatewayutil.GetGatewayRoutingPeer(ctx, r.Client, *gw) netRouter, err := gatewayutil.GetGatewayNetworkRouter(ctx, r.Client, gw)
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
if controllerutil.AddFinalizer(&tr, TCPRouteFinalizer) { controllerutil.AddFinalizer(tr, nbv1alpha1.NetbirdFinalizer)
err = r.Client.Update(ctx, &tr) err = sp.Patch(ctx, tr)
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
}
// Create network resources. // Create network resources.
svcIdx := map[string]corev1.Service{} svcIdx := map[string]corev1.Service{}
@@ -81,29 +77,23 @@ func (r *TCPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
} }
for _, svc := range svcIdx { for _, svc := range svcIdx {
nbResource := netbirdiov1.NBResource{ controllerRef, err := ssautil.ControllerReference(&svc, r.Scheme())
ObjectMeta: metav1.ObjectMeta{
Name: svc.Name,
Namespace: svc.Namespace,
},
}
_, err := controllerutil.CreateOrUpdate(ctx, r.Client, &nbResource, func() error {
err = controllerutil.SetControllerReference(&svc, &nbResource, r.Scheme(), controllerutil.WithBlockOwnerDeletion(false))
if err != nil { if err != nil {
return err return ctrl.Result{}, err
} }
err = controllerutil.SetOwnerReference(&tr, &nbResource, r.Scheme()) controllerRef = controllerRef.WithBlockOwnerDeletion(false)
ownerRef, err := ssautil.OwnerReference(tr, r.Scheme())
if err != nil { if err != nil {
return err return ctrl.Result{}, err
} }
nbResource.Spec = netbirdiov1.NBResourceSpec{ netResourceAC := nbv1alpha1ac.NetworkResource(svc.Name, svc.Namespace).
Name: svc.Name, WithOwnerReferences(controllerRef, ownerRef).
NetworkID: *nbrp.Status.NetworkID, WithSpec(
Address: fmt.Sprintf("%s.%s.%s", svc.Name, svc.Namespace, r.ClusterDNS), nbv1alpha1ac.NetworkResourceSpec().
Groups: []string{}, WithNetworkRouterRef(nbv1alpha1ac.CrossNamespaceReference().WithName(netRouter.Name).WithNamespace(netRouter.Namespace)).
} WithServiceRef(corev1.LocalObjectReference{Name: svc.Name}),
return nil )
}) err = r.Client.Apply(ctx, netResourceAC)
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
@@ -112,7 +102,7 @@ func (r *TCPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
return ctrl.Result{}, nil return ctrl.Result{}, nil
} }
func (r *TCPRouteReconciler) reconcileDelete(ctx context.Context, tr gatewayv1alpha2.TCPRoute) (ctrl.Result, error) { func (r *TCPRouteReconciler) reconcileDelete(ctx context.Context, sp *patch.SerialPatcher, tr *gatewayv1alpha2.TCPRoute) (ctrl.Result, error) {
for _, parent := range tr.Spec.ParentRefs { for _, parent := range tr.Spec.ParentRefs {
gw, err := gatewayutil.GetParentGateway(ctx, r.Client, parent, tr.Namespace, GatewayControllerName) gw, err := gatewayutil.GetParentGateway(ctx, r.Client, parent, tr.Namespace, GatewayControllerName)
if err != nil { if err != nil {
@@ -139,24 +129,29 @@ func (r *TCPRouteReconciler) reconcileDelete(ctx context.Context, tr gatewayv1al
} }
} }
for _, svc := range svcIdx { for _, svc := range svcIdx {
var nbResource netbirdiov1.NBResource netResource := &nbv1alpha1.NetworkResource{
err = r.Client.Get(ctx, client.ObjectKeyFromObject(&svc), &nbResource) ObjectMeta: metav1.ObjectMeta{
Name: svc.Name,
Namespace: svc.Namespace,
},
}
err = r.Client.Get(ctx, client.ObjectKeyFromObject(netResource), netResource)
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
err = controllerutil.RemoveOwnerReference(&tr, &nbResource, r.Scheme()) err = controllerutil.RemoveOwnerReference(tr, netResource, r.Scheme())
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
if len(nbResource.OwnerReferences) > 1 { if len(netResource.OwnerReferences) > 1 {
err = r.Client.Update(ctx, &nbResource) err = r.Client.Update(ctx, netResource)
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
} else { } else {
// TODO: Precondition that nothing has changed. // TODO: Precondition that nothing has changed.
err := r.Client.Delete(ctx, &nbResource) err := r.Client.Delete(ctx, netResource)
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
@@ -164,12 +159,11 @@ func (r *TCPRouteReconciler) reconcileDelete(ctx context.Context, tr gatewayv1al
} }
} }
if controllerutil.RemoveFinalizer(&tr, TCPRouteFinalizer) { controllerutil.RemoveFinalizer(tr, nbv1alpha1.NetbirdFinalizer)
err := r.Client.Update(ctx, &tr) err := sp.Patch(ctx, tr)
if err != nil { if err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
}
return ctrl.Result{}, nil return ctrl.Result{}, nil
} }
+10 -10
View File
@@ -10,7 +10,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
gwv1 "sigs.k8s.io/gateway-api/apis/v1" gwv1 "sigs.k8s.io/gateway-api/apis/v1"
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1" nbv1alpha1 "github.com/netbirdio/kubernetes-operator/api/v1alpha1"
) )
func GetParentGateway(ctx context.Context, k8sClient client.Client, parent gwv1.ParentReference, namespace, controllerName string) (*gwv1.Gateway, error) { func GetParentGateway(ctx context.Context, k8sClient client.Client, parent gwv1.ParentReference, namespace, controllerName string) (*gwv1.Gateway, error) {
@@ -36,29 +36,29 @@ func GetParentGateway(ctx context.Context, k8sClient client.Client, parent gwv1.
return gw, nil return gw, nil
} }
func GetGatewayRoutingPeer(ctx context.Context, k8sClient client.Client, gw gwv1.Gateway) (*netbirdiov1.NBRoutingPeer, error) { func GetGatewayNetworkRouter(ctx context.Context, k8sClient client.Client, gw *gwv1.Gateway) (*nbv1alpha1.NetworkRouter, error) {
routingPeerName, err := GetRoutingPeerName(gw.Spec.Listeners) netRouterName, err := GetNetworkRouterName(gw.Spec.Listeners)
if err != nil { if err != nil {
return nil, err return nil, err
} }
nbrp := &netbirdiov1.NBRoutingPeer{} netRouter := &nbv1alpha1.NetworkRouter{}
err = k8sClient.Get(ctx, types.NamespacedName{Namespace: gw.Namespace, Name: routingPeerName}, nbrp) err = k8sClient.Get(ctx, types.NamespacedName{Namespace: gw.Namespace, Name: netRouterName}, netRouter)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return nbrp, nil return netRouter, nil
} }
func GetRoutingPeerName(listeners []gwv1.Listener) (string, error) { func GetNetworkRouterName(listeners []gwv1.Listener) (string, error) {
if len(listeners) > 1 { if len(listeners) > 1 {
return "", errors.New("netbird Gateway only supports a single listener") return "", errors.New("netbird Gateway only supports a single listener")
} }
group, kind, ok := strings.Cut(string(listeners[0].Protocol), "/") group, kind, ok := strings.Cut(string(listeners[0].Protocol), "/")
if !ok { if !ok {
return "", fmt.Errorf("invalid protocol %s, expected gateway.netbird.io/NBRoutingPeer", listeners[0].Protocol) return "", fmt.Errorf("invalid protocol %s, expected gateway.netbird.io/NetworkRouter", listeners[0].Protocol)
} }
if group != "gateway.netbird.io" || kind != "NBRoutingPeer" { if group != "gateway.netbird.io" || kind != "NetworkRouter" {
return "", fmt.Errorf("invalid group %s and kind %s, expected gateway.netbird.io/NBRoutingPeer", group, kind) return "", fmt.Errorf("invalid group %s and kind %s, expected gateway.netbird.io/NetworkRouter", group, kind)
} }
return string(listeners[0].Name), nil return string(listeners[0].Name), nil
} }
+15 -1
View File
@@ -7,7 +7,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client/apiutil" "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
) )
func OwnerReference(owner client.Object, scheme *runtime.Scheme) (*metav1ac.OwnerReferenceApplyConfiguration, error) { func ControllerReference(owner client.Object, scheme *runtime.Scheme) (*metav1ac.OwnerReferenceApplyConfiguration, error) {
gvk, err := apiutil.GVKForObject(owner, scheme) gvk, err := apiutil.GVKForObject(owner, scheme)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -20,3 +20,17 @@ func OwnerReference(owner client.Object, scheme *runtime.Scheme) (*metav1ac.Owne
WithController(true). WithController(true).
WithBlockOwnerDeletion(true), nil WithBlockOwnerDeletion(true), nil
} }
func OwnerReference(owner client.Object, scheme *runtime.Scheme) (*metav1ac.OwnerReferenceApplyConfiguration, error) {
gvk, err := apiutil.GVKForObject(owner, scheme)
if err != nil {
return nil, err
}
return metav1ac.OwnerReference().
WithAPIVersion(gvk.GroupVersion().String()).
WithKind(gvk.Kind).
WithName(owner.GetName()).
WithUID(owner.GetUID()).
WithController(false).
WithBlockOwnerDeletion(false), nil
}