mirror of
https://github.com/YuzuZensai/netbird-kubernetes-operator.git
synced 2026-09-13 18:59:09 +00:00
Add support for private gateway (#154)
This change adds support for TCPRoutes when using a private gateway class. This is similar to annotating services today. It also moves the gateway classes to the Helm chart as it makes things a lot simpler for the end user as they no longer have to define them. Signed-off-by: Philip Laine <philip.laine@gmail.com>
This commit is contained in:
@@ -0,0 +1,181 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
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"
|
||||
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
|
||||
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
|
||||
|
||||
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1"
|
||||
"github.com/netbirdio/kubernetes-operator/internal/gatewayutil"
|
||||
)
|
||||
|
||||
const (
|
||||
TCPRouteFinalizer = "gateway.netbird.io/tcproute"
|
||||
)
|
||||
|
||||
type TCPRouteReconciler struct {
|
||||
client.Client
|
||||
|
||||
ClusterDNS string
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
tr := gatewayv1alpha2.TCPRoute{}
|
||||
err := r.Get(ctx, req.NamespacedName, &tr)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||
}
|
||||
|
||||
if !tr.DeletionTimestamp.IsZero() {
|
||||
return r.reconcileDelete(ctx, tr)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
if !meta.IsStatusConditionTrue(gw.Status.Conditions, string(gatewayv1.GatewayConditionProgrammed)) {
|
||||
logger.Info("gateway is not ready", "name", gw.ObjectMeta.Name)
|
||||
continue
|
||||
}
|
||||
nbrp, err := gatewayutil.GetGatewayRoutingPeer(ctx, r.Client, *gw)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
if controllerutil.AddFinalizer(&tr, TCPRouteFinalizer) {
|
||||
err = r.Client.Update(ctx, &tr)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
nbResource := netbirdiov1.NBResource{
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
err = controllerutil.SetOwnerReference(&tr, &nbResource, r.Scheme())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nbResource.Spec = netbirdiov1.NBResourceSpec{
|
||||
Name: svc.Name,
|
||||
NetworkID: *nbrp.Status.NetworkID,
|
||||
Address: fmt.Sprintf("%s.%s.%s", svc.Name, svc.Namespace, r.ClusterDNS),
|
||||
Groups: []string{},
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
func (r *TCPRouteReconciler) reconcileDelete(ctx context.Context, tr gatewayv1alpha2.TCPRoute) (ctrl.Result, error) {
|
||||
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 {
|
||||
var nbResource netbirdiov1.NBResource
|
||||
err = r.Client.Get(ctx, client.ObjectKeyFromObject(&svc), &nbResource)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
err = controllerutil.RemoveOwnerReference(&tr, &nbResource, r.Scheme())
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
if len(nbResource.OwnerReferences) > 1 {
|
||||
err = r.Client.Update(ctx, &nbResource)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
} else {
|
||||
// TODO: Precondition that nothing has changed.
|
||||
err := r.Client.Delete(ctx, &nbResource)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if controllerutil.RemoveFinalizer(&tr, TCPRouteFinalizer) {
|
||||
err := r.Client.Update(ctx, &tr)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
}
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
// SetupWithManager sets up the controller with the Manager.
|
||||
func (r *TCPRouteReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
For(&gatewayv1alpha2.TCPRoute{}).
|
||||
Complete(r)
|
||||
}
|
||||
Reference in New Issue
Block a user