diff --git a/cmd/main.go b/cmd/main.go index cfdc68b..814e984 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -76,6 +76,7 @@ func main() { netbirdAPIKey string allowAutomaticPolicyCreation bool defaultLabels string + routingPeerNamePrefix string ) flag.StringVar(&managementURL, "netbird-management-url", "https://api.netbird.io", "Management service URL") flag.StringVar(&clientImage, "netbird-client-image", "netbirdio/netbird:latest", "Image for netbird client container") @@ -105,6 +106,12 @@ func main() { "", "Default labels used for all resources, in format key=value,key=value", ) + flag.StringVar( + &routingPeerNamePrefix, + "routing-peer-name-prefix", + "", + "Prefix applied to routing peer names (final name becomes router)", + ) // Controller generic flags var ( @@ -255,6 +262,7 @@ func main() { NamespacedNetworks: namespacedNetworks, ControllerNamespace: controllerNamespace, DefaultLabels: defaultLabelsMap, + RouterNamePrefix: routingPeerNamePrefix, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "Service") os.Exit(1) diff --git a/docs/usage.md b/docs/usage.md index ad6ff94..221673e 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -62,8 +62,9 @@ With this setup, all peers with the same extra label would be used in a DNS roun 1. Alternatively, provision secret in the same namespace as the operator and set the key `NB_API_KEY` to the access token generated. 2. Set `netbirdAPI.keyFromSecret` to the name of the secret created. 4. Set `ingress.enabled` to `true`. - 1. Optionally, to provision the network immediately, set `ingress.router.enabled` to `true`. - 2. Optionally, to provision 1 network per namespace, set `ingress.namespacedNetworks` to `true`. + 1. Optionally, to provision the network immediately, set `ingress.router.enabled` to `true`. + 2. Optionally, to provision 1 network per namespace, set `ingress.namespacedNetworks` to `true`. + 3. Optionally, set `ingress.router.namePrefix` to prepend a custom string to every routing peer name (resulting name becomes `-router`). 5. Run `helm install` or `helm upgrade`. Minimum values.yaml example: diff --git a/examples/ingress/values.yaml b/examples/ingress/values.yaml index a310b76..bf08701 100644 --- a/examples/ingress/values.yaml +++ b/examples/ingress/values.yaml @@ -5,6 +5,7 @@ ingress: enabled: true router: enabled: true + # namePrefix: "demo-" # policies: # default: # name: Kubernetes Default Policy diff --git a/helm/kubernetes-operator/templates/deployment.yaml b/helm/kubernetes-operator/templates/deployment.yaml index 117b3eb..c491de5 100644 --- a/helm/kubernetes-operator/templates/deployment.yaml +++ b/helm/kubernetes-operator/templates/deployment.yaml @@ -54,6 +54,9 @@ spec: {{- if .Values.ingress.namespacedNetworks }} - --namespaced-networks={{.Values.ingress.namespacedNetworks}} {{- end }} + {{- if .Values.ingress.router.namePrefix }} + - --routing-peer-name-prefix={{ .Values.ingress.router.namePrefix }} + {{- end }} {{- if .Values.cluster.dns }} - --cluster-dns={{.Values.cluster.dns}} {{- end }} diff --git a/helm/kubernetes-operator/templates/kubernetes-nbresource.yaml b/helm/kubernetes-operator/templates/kubernetes-nbresource.yaml index 375366f..6682ef2 100644 --- a/helm/kubernetes-operator/templates/kubernetes-nbresource.yaml +++ b/helm/kubernetes-operator/templates/kubernetes-nbresource.yaml @@ -3,6 +3,10 @@ {{- if .Values.ingress.namespacedNetworks }} {{- $routerNS = "default" }} {{- end }} +{{- $routerName := "router" }} +{{- if .Values.ingress.router.namePrefix }} +{{- $routerName = printf "%s-router" .Values.ingress.router.namePrefix }} +{{- end }} apiVersion: batch/v1 kind: Job metadata: @@ -32,7 +36,7 @@ spec: - bash - -c args: - - kubectl wait --for 'jsonpath={.status.networkID}' -n {{ $routerNS }} nbroutingpeer router; + - kubectl wait --for 'jsonpath={.status.networkID}' -n {{ $routerNS }} nbroutingpeer {{ $routerName }}; containers: - name: apply-nbresource image: "bitnami/kubectl:latest" @@ -47,10 +51,14 @@ spec: name: kubernetes namespace: default spec: + {{- if .Values.cluster.apiserver }} + address: {{ .Values.cluster.apiserver }} + {{- else }} address: kubernetes.default.{{.Values.cluster.dns}} + {{- end }} groups: {{- if .Values.ingress.kubernetesAPI.groups }} - {{ toYaml .Values.ingress.kubernetesAPI.groups }} + {{ toYaml .Values.ingress.kubernetesAPI.groups | nindent 14 }} {{- else }} - {{ .Values.cluster.name }}-default-api-access {{- end }} @@ -65,7 +73,7 @@ spec: - bash - -c args: - - kubectl delete NBResource --ignore-not-found -n default kubernetes; export NETWORK_ID=$(kubectl get NBRoutingPeer -n {{ $routerNS }} router -o 'jsonpath={.status.networkID}'); echo "$NBRESOURCE_VALUE" | envsubst | kubectl apply -f - + - kubectl delete NBResource --ignore-not-found -n default kubernetes; export NETWORK_ID=$(kubectl get NBRoutingPeer -n {{ $routerNS }} {{ $routerName }} -o 'jsonpath={.status.networkID}'); echo "$NBRESOURCE_VALUE" | envsubst | kubectl apply -f - serviceAccountName: {{ include "kubernetes-operator.serviceAccountName" . }} restartPolicy: Never {{- end }} diff --git a/helm/kubernetes-operator/templates/nbroutingpeers.yaml b/helm/kubernetes-operator/templates/nbroutingpeers.yaml index 7742b41..d160d9a 100644 --- a/helm/kubernetes-operator/templates/nbroutingpeers.yaml +++ b/helm/kubernetes-operator/templates/nbroutingpeers.yaml @@ -1,4 +1,6 @@ {{- if and .Values.ingress.enabled .Values.ingress.router.enabled }} +{{- $routerNamePrefix := default "" .Values.ingress.router.namePrefix }} +{{- $routerResourceName := printf "%s-%s" $routerNamePrefix "router" }} {{- if .Values.ingress.namespacedNetworks }} {{ $defaults := .Values.ingress.router }} {{ range $k, $v := .Values.ingress.router.namespaces }} @@ -10,9 +12,9 @@ metadata: labels: app.kubernetes.io/component: operator {{- include "kubernetes-operator.labels" $ | nindent 4 }} - name: router + name: {{ $routerResourceName }} namespace: {{ $k }} -{{ $spec := merge $defaults $v }} +{{ $spec := merge (dict) $defaults $v }} {{- if or (or (or $spec.replicas $spec.resources) (or $spec.labels $spec.annotations)) (or $spec.nodeSelector $spec.tolerations) }} spec: {{- if $spec.replicas }} @@ -51,7 +53,7 @@ metadata: labels: app.kubernetes.io/component: operator {{- include "kubernetes-operator.labels" $ | nindent 4 }} - name: router + name: {{ $routerResourceName }} {{- if or (or (or .replicas .resources) (or .labels .annotations)) (or .nodeSelector .tolerations) }} spec: {{- if .replicas }} diff --git a/helm/kubernetes-operator/values.yaml b/helm/kubernetes-operator/values.yaml index b02113a..982f4e9 100644 --- a/helm/kubernetes-operator/values.yaml +++ b/helm/kubernetes-operator/values.yaml @@ -150,6 +150,8 @@ ingress: router: # Deploy routing peer(s) enabled: false + # Prefix appended to routing peer names (final name becomes router) + namePrefix: "" # replicas: 3 # resources: # requests: @@ -187,6 +189,8 @@ ingress: cluster: # Cluster DNS name (used for webhooks certificates and for network resource DNS names) dns: svc.cluster.local + # Cluster API server address (overrides in-cluster address detection) + # apiserver: https://my-custom-apiserver:6443 # Cluster name (used for generating network and network resource names in NetBird) name: kubernetes diff --git a/internal/controller/service_controller.go b/internal/controller/service_controller.go index dd26e2d..927ea14 100644 --- a/internal/controller/service_controller.go +++ b/internal/controller/service_controller.go @@ -28,6 +28,7 @@ type ServiceReconciler struct { NamespacedNetworks bool ControllerNamespace string DefaultLabels map[string]string + RouterNamePrefix string } const ( @@ -40,6 +41,7 @@ const ( serviceProtocolAnnotation = "netbird.io/policy-protocol" servicePolicySourceGroupsAnnotation = "netbird.io/policy-source-groups" servicePolicyNameAnnotation = "netbird.io/policy-name" + routingPeerBaseName = "router" ) var ( @@ -114,6 +116,7 @@ func (r *ServiceReconciler) exposeService(ctx context.Context, req ctrl.Request, if r.NamespacedNetworks { routerNamespace = req.Namespace } + routerName := r.routingPeerName() if !util.Contains(svc.Finalizers, "netbird.io/cleanup") { svc.Finalizers = append(svc.Finalizers, "netbird.io/cleanup") @@ -126,7 +129,7 @@ func (r *ServiceReconciler) exposeService(ctx context.Context, req ctrl.Request, var routingPeer netbirdiov1.NBRoutingPeer // Check if NBRoutingPeer exists - err := r.Client.Get(ctx, types.NamespacedName{Namespace: routerNamespace, Name: "router"}, &routingPeer) + err := r.Client.Get(ctx, types.NamespacedName{Namespace: routerNamespace, Name: routerName}, &routingPeer) if err != nil && !errors.IsNotFound(err) { logger.Error(errKubernetesAPI, "error getting NBRoutingPeer", "err", err) return ctrl.Result{}, err @@ -136,7 +139,7 @@ func (r *ServiceReconciler) exposeService(ctx context.Context, req ctrl.Request, if errors.IsNotFound(err) { routingPeer = netbirdiov1.NBRoutingPeer{ ObjectMeta: v1.ObjectMeta{ - Name: "router", + Name: routerName, Namespace: routerNamespace, Finalizers: []string{"netbird.io/cleanup"}, Labels: r.DefaultLabels, @@ -294,6 +297,10 @@ func (r *ServiceReconciler) applyPolicy(nbResource *netbirdiov1.NBResource, svc return nil } +func (r *ServiceReconciler) routingPeerName() string { + return fmt.Sprintf("%s-%s", r.RouterNamePrefix, routingPeerBaseName) +} + // SetupWithManager sets up the controller with the Manager. func (r *ServiceReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). diff --git a/internal/controller/service_controller_test.go b/internal/controller/service_controller_test.go index 6077c30..8e1262f 100644 --- a/internal/controller/service_controller_test.go +++ b/internal/controller/service_controller_test.go @@ -86,9 +86,13 @@ var _ = Describe("Service Controller", func() { } } - nbrp := &netbirdiov1.NBRoutingPeer{} - err = k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "router"}, nbrp) - if !errors.IsNotFound(err) { + nbrpList := &netbirdiov1.NBRoutingPeerList{} + Expect(k8sClient.List(ctx, nbrpList)).To(Succeed()) + for i := range nbrpList.Items { + nbrp := &nbrpList.Items[i] + if nbrp.Namespace != typeNamespacedName.Namespace { + continue + } if len(nbrp.Finalizers) > 0 { nbrp.Finalizers = nil Expect(k8sClient.Update(ctx, nbrp)).To(Succeed()) @@ -144,7 +148,7 @@ var _ = Describe("Service Controller", func() { Expect(err).NotTo(HaveOccurred()) Expect(res.RequeueAfter).NotTo(BeZero()) nbrp := &netbirdiov1.NBRoutingPeer{} - Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: typeNamespacedName.Namespace, Name: "router"}, nbrp)).To(Succeed()) + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: typeNamespacedName.Namespace, Name: controllerReconciler.routingPeerName()}, nbrp)).To(Succeed()) Expect(nbrp.Labels).To(HaveKeyWithValue("dog", "bark")) res, err = controllerReconciler.Reconcile(ctx, reconcile.Request{ NamespacedName: typeNamespacedName, @@ -159,13 +163,28 @@ var _ = Describe("Service Controller", func() { Expect(err).NotTo(HaveOccurred()) Expect(res.RequeueAfter).To(BeZero()) }) + It("should honor router name prefix when creating NBRoutingPeer", func() { + controllerReconciler.RouterNamePrefix = "custom-" + defer func() { + controllerReconciler.RouterNamePrefix = "" + }() + + _, err := controllerReconciler.Reconcile(ctx, reconcile.Request{ + NamespacedName: typeNamespacedName, + }) + Expect(err).NotTo(HaveOccurred()) + nbrp := &netbirdiov1.NBRoutingPeer{} + expectedName := controllerReconciler.RouterNamePrefix + routingPeerBaseName + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: typeNamespacedName.Namespace, Name: expectedName}, nbrp)).To(Succeed()) + Expect(nbrp.Name).To(Equal("custom-router")) + }) }) When("NBRoutingPeer exists", func() { BeforeEach(func() { nbrp := &netbirdiov1.NBRoutingPeer{ ObjectMeta: v1.ObjectMeta{ Namespace: typeNamespacedName.Namespace, - Name: "router", + Name: controllerReconciler.routingPeerName(), }, Spec: netbirdiov1.NBRoutingPeerSpec{}, } @@ -313,7 +332,7 @@ var _ = Describe("Service Controller", func() { nbrp := &netbirdiov1.NBRoutingPeer{ ObjectMeta: v1.ObjectMeta{ Namespace: typeNamespacedName.Namespace, - Name: "router", + Name: controllerReconciler.routingPeerName(), }, Spec: netbirdiov1.NBRoutingPeerSpec{}, }