mirror of
https://github.com/YuzuZensai/netbird-kubernetes-operator.git
synced 2026-09-13 18:59:09 +00:00
Refactor uninstallation process (#74)
Docs PR: https://github.com/netbirdio/docs/pull/457 Changes: * Split kubernetes-operator Chart to operator only chart (kubernetes-operator) and configuration chart (netbird-operator-config) * Remove delete validation webhooks for non-needed resources * Allow abandoning Groups when still linked to a resource for over a minute after deletion * Fix duplciate Network Resource retrying heavily * Fix SetupKey creation duplication * Skip deleting routing peer since deleting network automatically deletes it anyway
This commit is contained in:
@@ -5,6 +5,7 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
# update this file to trigger helm chart release
|
# update this file to trigger helm chart release
|
||||||
- 'helm/kubernetes-operator/Chart.yaml'
|
- 'helm/kubernetes-operator/Chart.yaml'
|
||||||
|
- 'helm/netbird-operator-config/Chart.yaml'
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
name: Docker
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- 'Dockerfile.kubectl'
|
||||||
|
tags:
|
||||||
|
- "v*"
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
kubectl-docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
# This is used to complete the identity challenge
|
||||||
|
# with sigstore/fulcio when running outside of PRs.
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Docker meta
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v5
|
||||||
|
with:
|
||||||
|
# list of Docker images to use as base name for tags
|
||||||
|
images: |
|
||||||
|
netbirdio/kubectl
|
||||||
|
# generate Docker tags based on the following events/attributes
|
||||||
|
tags: |
|
||||||
|
type=ref,event=pr
|
||||||
|
type=ref,event=branch
|
||||||
|
type=semver,pattern={{version}}
|
||||||
|
|
||||||
|
- name: Login to Docker Hub
|
||||||
|
if: github.repository == github.event.pull_request.head.repo.full_name || !github.head_ref
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USER }}
|
||||||
|
password: ${{ secrets.DOCKER_TOKEN }}
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
file: "Dockerfile.kubectl"
|
||||||
|
labels: |
|
||||||
|
"org.opencontainers.image.created={{.Date}}"
|
||||||
|
"org.opencontainers.image.title={{.ProjectName}}"
|
||||||
|
"org.opencontainers.image.version={{.Version}}"
|
||||||
|
"org.opencontainers.image.revision={{.FullCommit}}"
|
||||||
|
"org.opencontainers.image.version={{.Version}}"
|
||||||
|
"maintainer=dev@netbird.io"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
FROM alpine:3 AS builder
|
||||||
|
|
||||||
|
RUN apk update && apk add curl
|
||||||
|
RUN curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" && \
|
||||||
|
chmod +x kubectl && \
|
||||||
|
mv kubectl /usr/local/bin/kubectl
|
||||||
|
|
||||||
|
FROM alpine:3 AS final
|
||||||
|
|
||||||
|
COPY --from=builder /usr/local/bin/kubectl /usr/local/bin/kubectl
|
||||||
-10
@@ -294,16 +294,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if enableWebhooks {
|
if enableWebhooks {
|
||||||
if err = webhooknetbirdiov1.SetupNBResourceWebhookWithManager(mgr); err != nil {
|
|
||||||
setupLog.Error(err, "unable to create webhook", "webhook", "NBResource")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = webhooknetbirdiov1.SetupNBRoutingPeerWebhookWithManager(mgr); err != nil {
|
|
||||||
setupLog.Error(err, "unable to create webhook", "webhook", "NBRoutingPeer")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = webhooknetbirdiov1.SetupNBGroupWebhookWithManager(mgr); err != nil {
|
if err = webhooknetbirdiov1.SetupNBGroupWebhookWithManager(mgr); err != nil {
|
||||||
setupLog.Error(err, "unable to create webhook", "webhook", "NBGroup")
|
setupLog.Error(err, "unable to create webhook", "webhook", "NBGroup")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|||||||
@@ -3,13 +3,6 @@
|
|||||||
# tag: "0.1.0"
|
# tag: "0.1.0"
|
||||||
ingress:
|
ingress:
|
||||||
enabled: true
|
enabled: true
|
||||||
router:
|
|
||||||
enabled: true
|
|
||||||
# policies:
|
|
||||||
# default:
|
|
||||||
# name: Kubernetes Default Policy
|
|
||||||
# sourceGroups:
|
|
||||||
# - All
|
|
||||||
|
|
||||||
netbirdAPI:
|
netbirdAPI:
|
||||||
# Replace with valid NetBird Service Account token (PAT)
|
# Replace with valid NetBird Service Account token (PAT)
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
router:
|
||||||
|
enabled: true
|
||||||
|
policies:
|
||||||
|
default:
|
||||||
|
name: Kubernetes Default Policy
|
||||||
|
sourceGroups:
|
||||||
|
- All
|
||||||
@@ -2,5 +2,5 @@ apiVersion: v2
|
|||||||
name: kubernetes-operator
|
name: kubernetes-operator
|
||||||
description: NetBird Kubernetes Operator
|
description: NetBird Kubernetes Operator
|
||||||
type: application
|
type: application
|
||||||
version: 0.1.15
|
version: 0.2.0
|
||||||
appVersion: "0.1.5"
|
appVersion: "0.2.0"
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
initContainers:
|
initContainers:
|
||||||
- name: wait-network-ready
|
- name: wait-network-ready
|
||||||
image: "bitnami/kubectl:latest"
|
image: "netbirdio/kubectl:latest"
|
||||||
command:
|
command:
|
||||||
- bash
|
- bash
|
||||||
- -c
|
- -c
|
||||||
@@ -35,7 +35,7 @@ spec:
|
|||||||
- kubectl wait --for 'jsonpath={.status.networkID}' -n {{ $routerNS }} nbroutingpeer router;
|
- kubectl wait --for 'jsonpath={.status.networkID}' -n {{ $routerNS }} nbroutingpeer router;
|
||||||
containers:
|
containers:
|
||||||
- name: apply-nbresource
|
- name: apply-nbresource
|
||||||
image: "bitnami/kubectl:latest"
|
image: "netbirdio/kubectl:latest"
|
||||||
env:
|
env:
|
||||||
- name: NBRESOURCE_VALUE
|
- name: NBRESOURCE_VALUE
|
||||||
value: |
|
value: |
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ metadata:
|
|||||||
labels:
|
labels:
|
||||||
app.kubernetes.io/component: operator
|
app.kubernetes.io/component: operator
|
||||||
{{- include "kubernetes-operator.labels" $ | nindent 4 }}
|
{{- include "kubernetes-operator.labels" $ | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
helm.sh/resource-policy: keep
|
||||||
name: {{ $k }}
|
name: {{ $k }}
|
||||||
spec:
|
spec:
|
||||||
name: {{ $v.name }}
|
name: {{ $v.name }}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ metadata:
|
|||||||
labels:
|
labels:
|
||||||
app.kubernetes.io/component: operator
|
app.kubernetes.io/component: operator
|
||||||
{{- include "kubernetes-operator.labels" $ | nindent 4 }}
|
{{- include "kubernetes-operator.labels" $ | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
helm.sh/resource-policy: keep
|
||||||
name: router
|
name: router
|
||||||
namespace: {{ $k }}
|
namespace: {{ $k }}
|
||||||
{{ $spec := merge $defaults $v }}
|
{{ $spec := merge $defaults $v }}
|
||||||
@@ -51,6 +53,8 @@ metadata:
|
|||||||
labels:
|
labels:
|
||||||
app.kubernetes.io/component: operator
|
app.kubernetes.io/component: operator
|
||||||
{{- include "kubernetes-operator.labels" $ | nindent 4 }}
|
{{- include "kubernetes-operator.labels" $ | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
helm.sh/resource-policy: keep
|
||||||
name: router
|
name: router
|
||||||
{{- if or (or (or .replicas .resources) (or .labels .annotations)) (or .nodeSelector .tolerations) }}
|
{{- if or (or (or .replicas .resources) (or .labels .annotations)) (or .nodeSelector .tolerations) }}
|
||||||
spec:
|
spec:
|
||||||
|
|||||||
@@ -1,69 +1,41 @@
|
|||||||
apiVersion: batch/v1
|
{{/*apiVersion: batch/v1*/}}
|
||||||
kind: Job
|
{{/*kind: Job*/}}
|
||||||
metadata:
|
{{/*metadata:*/}}
|
||||||
name: {{ include "kubernetes-operator.fullname" . }}-delete-routers
|
{{/* name: {{ include "kubernetes-operator.fullname" . }}-delete-router-deployments*/}}
|
||||||
labels:
|
{{/* labels:*/}}
|
||||||
app.kubernetes.io/component: operator
|
{{/* app.kubernetes.io/component: operator*/}}
|
||||||
{{- include "kubernetes-operator.labels" . | nindent 4 }}
|
{{/* {{- include "kubernetes-operator.labels" . | nindent 4 }}*/}}
|
||||||
annotations:
|
{{/* annotations:*/}}
|
||||||
helm.sh/hook: pre-delete
|
{{/* helm.sh/hook: pre-delete*/}}
|
||||||
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
|
{{/* helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded*/}}
|
||||||
spec:
|
{{/*spec:*/}}
|
||||||
backoffLimit: 3
|
{{/* backoffLimit: 3*/}}
|
||||||
template:
|
{{/* template:*/}}
|
||||||
metadata:
|
{{/* metadata:*/}}
|
||||||
name: {{ include "kubernetes-operator.fullname" . }}
|
{{/* name: {{ include "kubernetes-operator.fullname" . }}*/}}
|
||||||
labels:
|
{{/* labels:*/}}
|
||||||
app.kubernetes.io/component: operator
|
{{/* app.kubernetes.io/component: operator*/}}
|
||||||
{{- include "kubernetes-operator.labels" . | nindent 8 }}
|
{{/* {{- include "kubernetes-operator.labels" . | nindent 8 }}*/}}
|
||||||
{{- with .Values.operator.podLabels }}
|
{{/* {{- with .Values.operator.podLabels }}*/}}
|
||||||
{{- toYaml . | nindent 8 }}
|
{{/* {{- toYaml . | nindent 8 }}*/}}
|
||||||
{{- end }}
|
{{/* {{- end }}*/}}
|
||||||
spec:
|
{{/* spec:*/}}
|
||||||
containers:
|
{{/* containers:*/}}
|
||||||
- name: pre-delete
|
{{/* - name: pre-delete*/}}
|
||||||
image: "bitnami/kubectl:latest"
|
{{/* image: "netbirdio/kubectl:latest"*/}}
|
||||||
args:
|
{{/* imagePullPolicy: {{ .Values.operator.image.pullPolicy }}*/}}
|
||||||
- delete
|
{{/* command:*/}}
|
||||||
- --all
|
{{/* - sh*/}}
|
||||||
- -A
|
{{/* - -c*/}}
|
||||||
- --cascade=foreground
|
{{/* args:*/}}
|
||||||
- --ignore-not-found
|
{{/* - kubectl get NBRoutingPeer -A --no-headers -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name | while read "L"; do kubectl patch --type=json -p '[{"op":"replace","path":"/spec/disableDeployment","value":true}]' NBRoutingPeer -n $(echo "$L" | awk '{print $1}') $(echo "$L" | awk '{print $2}'); done*/}}
|
||||||
- NBRoutingPeer
|
{{/* - name: delete-wait*/}}
|
||||||
serviceAccountName: {{ include "kubernetes-operator.serviceAccountName" . }}
|
{{/* image: "netbirdio/kubectl:latest"*/}}
|
||||||
restartPolicy: Never
|
{{/* imagePullPolicy: {{ .Values.operator.image.pullPolicy }}*/}}
|
||||||
---
|
{{/* command:*/}}
|
||||||
apiVersion: batch/v1
|
{{/* - sh*/}}
|
||||||
kind: Job
|
{{/* - -c*/}}
|
||||||
metadata:
|
{{/* args:*/}}
|
||||||
name: {{ include "kubernetes-operator.fullname" . }}-delete-policies
|
{{/* - kubectl get NBRoutingPeer -A --no-headers -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name | while read "L"; do kubectl wait --for=delete deployment -n $(echo "$L" | awk '{print $1}') $(echo "$L" | awk '{print $2}'); done*/}}
|
||||||
labels:
|
{{/* serviceAccountName: {{ include "kubernetes-operator.serviceAccountName" . }}*/}}
|
||||||
app.kubernetes.io/component: operator
|
{{/* restartPolicy: Never*/}}
|
||||||
{{- include "kubernetes-operator.labels" . | nindent 4 }}
|
|
||||||
annotations:
|
|
||||||
helm.sh/hook: pre-delete
|
|
||||||
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
|
|
||||||
spec:
|
|
||||||
backoffLimit: 3
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
name: {{ include "kubernetes-operator.fullname" . }}
|
|
||||||
labels:
|
|
||||||
app.kubernetes.io/component: operator
|
|
||||||
{{- include "kubernetes-operator.labels" . | nindent 8 }}
|
|
||||||
{{- with .Values.operator.podLabels }}
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: pre-delete
|
|
||||||
image: "bitnami/kubectl:latest"
|
|
||||||
args:
|
|
||||||
- delete
|
|
||||||
- --all
|
|
||||||
- --cascade=foreground
|
|
||||||
- --ignore-not-found
|
|
||||||
- NBPolicy
|
|
||||||
serviceAccountName: {{ include "kubernetes-operator.serviceAccountName" . }}
|
|
||||||
restartPolicy: Never
|
|
||||||
---
|
|
||||||
|
|||||||
@@ -96,84 +96,6 @@ webhooks:
|
|||||||
apiVersion: admissionregistration.k8s.io/v1
|
apiVersion: admissionregistration.k8s.io/v1
|
||||||
kind: ValidatingWebhookConfiguration
|
kind: ValidatingWebhookConfiguration
|
||||||
metadata:
|
metadata:
|
||||||
{{- if $.Values.webhook.enableCertManager }}
|
|
||||||
annotations:
|
|
||||||
cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ template "kubernetes-operator.fullname" . }}-serving-cert
|
|
||||||
{{- end }}
|
|
||||||
name: {{ include "kubernetes-operator.fullname" . }}-vnbresource-webhook
|
|
||||||
labels:
|
|
||||||
{{- include "kubernetes-operator.labels" . | nindent 4 }}
|
|
||||||
webhooks:
|
|
||||||
- clientConfig:
|
|
||||||
{{- if not $.Values.webhook.enableCertManager }}
|
|
||||||
caBundle: {{ $tls.caCert }}
|
|
||||||
{{ end }}
|
|
||||||
service:
|
|
||||||
name: {{ template "kubernetes-operator.webhookService" . }}
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
path: /validate-netbird-io-v1-nbresource
|
|
||||||
failurePolicy: {{ .Values.webhook.failurePolicy }}
|
|
||||||
name: vnbresource-v1.netbird.io
|
|
||||||
admissionReviewVersions:
|
|
||||||
- v1
|
|
||||||
{{- if .Values.webhook.namespaceSelectors }}
|
|
||||||
namespaceSelector:
|
|
||||||
matchExpressions:
|
|
||||||
{{ toYaml .Values.webhook.namespaceSelectors | nindent 4 }}
|
|
||||||
{{ end }}
|
|
||||||
rules:
|
|
||||||
- apiGroups:
|
|
||||||
- netbird.io
|
|
||||||
apiVersions:
|
|
||||||
- v1
|
|
||||||
operations:
|
|
||||||
- DELETE
|
|
||||||
resources:
|
|
||||||
- "nbresources"
|
|
||||||
sideEffects: None
|
|
||||||
---
|
|
||||||
apiVersion: admissionregistration.k8s.io/v1
|
|
||||||
kind: ValidatingWebhookConfiguration
|
|
||||||
metadata:
|
|
||||||
{{- if $.Values.webhook.enableCertManager }}
|
|
||||||
annotations:
|
|
||||||
cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ template "kubernetes-operator.fullname" . }}-serving-cert
|
|
||||||
{{- end }}
|
|
||||||
name: {{ include "kubernetes-operator.fullname" . }}-vnbroutingpeer-webhook
|
|
||||||
labels:
|
|
||||||
{{- include "kubernetes-operator.labels" . | nindent 4 }}
|
|
||||||
webhooks:
|
|
||||||
- clientConfig:
|
|
||||||
{{- if not $.Values.webhook.enableCertManager }}
|
|
||||||
caBundle: {{ $tls.caCert }}
|
|
||||||
{{ end }}
|
|
||||||
service:
|
|
||||||
name: {{ template "kubernetes-operator.webhookService" . }}
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
path: /validate-netbird-io-v1-nbroutingpeer
|
|
||||||
failurePolicy: {{ .Values.webhook.failurePolicy }}
|
|
||||||
name: vnbroutingpeer-v1.netbird.io
|
|
||||||
admissionReviewVersions:
|
|
||||||
- v1
|
|
||||||
{{- if .Values.webhook.namespaceSelectors }}
|
|
||||||
namespaceSelector:
|
|
||||||
matchExpressions:
|
|
||||||
{{ toYaml .Values.webhook.namespaceSelectors | nindent 4 }}
|
|
||||||
{{ end }}
|
|
||||||
rules:
|
|
||||||
- apiGroups:
|
|
||||||
- netbird.io
|
|
||||||
apiVersions:
|
|
||||||
- v1
|
|
||||||
operations:
|
|
||||||
- DELETE
|
|
||||||
resources:
|
|
||||||
- "nbroutingpeers"
|
|
||||||
sideEffects: None
|
|
||||||
---
|
|
||||||
apiVersion: admissionregistration.k8s.io/v1
|
|
||||||
kind: ValidatingWebhookConfiguration
|
|
||||||
metadata:
|
|
||||||
{{- if $.Values.webhook.enableCertManager }}
|
{{- if $.Values.webhook.enableCertManager }}
|
||||||
annotations:
|
annotations:
|
||||||
cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ template "kubernetes-operator.fullname" . }}-serving-cert
|
cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ template "kubernetes-operator.fullname" . }}-serving-cert
|
||||||
|
|||||||
@@ -140,14 +140,14 @@ ingress:
|
|||||||
namespacedNetworks: false
|
namespacedNetworks: false
|
||||||
# Allow creating policies through Service annotations
|
# Allow creating policies through Service annotations
|
||||||
allowAutomaticPolicyCreation: false
|
allowAutomaticPolicyCreation: false
|
||||||
kubernetesAPI:
|
kubernetesAPI: # DEPRECATED: Use netbirdio/netbird-operator-configs Chart instead
|
||||||
enabled: false
|
enabled: false
|
||||||
groups: []
|
groups: []
|
||||||
# - group1
|
# - group1
|
||||||
# - group2
|
# - group2
|
||||||
policies: []
|
policies: []
|
||||||
# - default
|
# - default
|
||||||
router:
|
router: # DEPRECATED: Use netbirdio/netbird-operator-configs Chart instead
|
||||||
# Deploy routing peer(s)
|
# Deploy routing peer(s)
|
||||||
enabled: false
|
enabled: false
|
||||||
# replicas: 3
|
# replicas: 3
|
||||||
@@ -178,7 +178,7 @@ ingress:
|
|||||||
# nodeSelector: {}
|
# nodeSelector: {}
|
||||||
# tolerations: []
|
# tolerations: []
|
||||||
# NetBird Policies for use with exposed services
|
# NetBird Policies for use with exposed services
|
||||||
policies: {}
|
policies: {} # DEPRECATED: Use netbirdio/netbird-operator-configs Chart instead
|
||||||
# default:
|
# default:
|
||||||
# name: Kubernetes Default Policy
|
# name: Kubernetes Default Policy
|
||||||
# sourceGroups:
|
# sourceGroups:
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Patterns to ignore when building packages.
|
||||||
|
# This supports shell glob matching, relative path matching, and
|
||||||
|
# negation (prefixed with !). Only one pattern per line.
|
||||||
|
.DS_Store
|
||||||
|
# Common VCS dirs
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
.bzr/
|
||||||
|
.bzrignore
|
||||||
|
.hg/
|
||||||
|
.hgignore
|
||||||
|
.svn/
|
||||||
|
# Common backup files
|
||||||
|
*.swp
|
||||||
|
*.bak
|
||||||
|
*.tmp
|
||||||
|
*.orig
|
||||||
|
*~
|
||||||
|
# Various IDEs
|
||||||
|
.project
|
||||||
|
.idea/
|
||||||
|
*.tmproj
|
||||||
|
.vscode/
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: netbird-operator-config
|
||||||
|
description: A Helm chart for Kubernetes
|
||||||
|
type: application
|
||||||
|
version: 0.1.0
|
||||||
|
appVersion: "0.0.0"
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
{{/*
|
||||||
|
Create a default fully qualified app name.
|
||||||
|
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||||
|
If release name contains chart name it will be used as a full name.
|
||||||
|
*/}}
|
||||||
|
{{- define "netbird-operator-config.fullname" -}}
|
||||||
|
{{- if .Values.fullnameOverride }}
|
||||||
|
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- else }}
|
||||||
|
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||||
|
{{- if contains $name .Release.Name }}
|
||||||
|
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- else }}
|
||||||
|
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Expand the name of the chart.
|
||||||
|
*/}}
|
||||||
|
{{- define "netbird-operator-config.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create chart name and version as used by the chart label.
|
||||||
|
*/}}
|
||||||
|
{{- define "netbird-operator-config.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Common labels
|
||||||
|
*/}}
|
||||||
|
{{- define "netbird-operator-config.labels" -}}
|
||||||
|
helm.sh/chart: {{ include "netbird-operator-config.chart" . }}
|
||||||
|
{{ include "netbird-operator-config.selectorLabels" . }}
|
||||||
|
{{- if .Chart.AppVersion }}
|
||||||
|
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||||
|
{{- end }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Selector labels
|
||||||
|
*/}}
|
||||||
|
{{- define "netbird-operator-config.selectorLabels" -}}
|
||||||
|
app.kubernetes.io/name: {{ include "netbird-operator-config.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create the name of the service account to use
|
||||||
|
*/}}
|
||||||
|
{{- define "netbird-operator-config.serviceAccountName" -}}
|
||||||
|
{{- if .Values.serviceAccount.create }}
|
||||||
|
{{- default (include "netbird-operator-config.fullname" .) .Values.serviceAccount.name }}
|
||||||
|
{{- else }}
|
||||||
|
{{- default "default" .Values.serviceAccount.name }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
{{- if and .Values.ingress.enabled .Values.ingress.kubernetesAPI.enabled }}
|
||||||
|
{{- $routerNS := .Release.Namespace }}
|
||||||
|
{{- if .Values.ingress.namespacedNetworks }}
|
||||||
|
{{- $routerNS = "default" }}
|
||||||
|
{{- end }}
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
name: {{ include "netbird-operator-config.fullname" . }}-kubernetes-service-expose
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/component: operator
|
||||||
|
{{- include "netbird-operator-config.labels" . | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
helm.sh/hook: post-upgrade,post-install
|
||||||
|
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
|
||||||
|
spec:
|
||||||
|
backoffLimit: 3
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
name: {{ include "netbird-operator-config.fullname" . }}
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/component: operator
|
||||||
|
{{- include "netbird-operator-config.labels" . | nindent 8 }}
|
||||||
|
{{- with .Values.operator.podLabels }}
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
initContainers:
|
||||||
|
- name: wait-network-ready
|
||||||
|
image: "netbirdio/kubectl:latest"
|
||||||
|
command:
|
||||||
|
- bash
|
||||||
|
- -c
|
||||||
|
args:
|
||||||
|
- kubectl wait --for 'jsonpath={.status.networkID}' -n {{ $routerNS }} nbroutingpeer router;
|
||||||
|
containers:
|
||||||
|
- name: apply-nbresource
|
||||||
|
image: "netbirdio/kubectl:latest"
|
||||||
|
env:
|
||||||
|
- name: NBRESOURCE_VALUE
|
||||||
|
value: |
|
||||||
|
apiVersion: netbird.io/v1
|
||||||
|
kind: NBResource
|
||||||
|
metadata:
|
||||||
|
finalizers:
|
||||||
|
- netbird.io/cleanup
|
||||||
|
name: kubernetes
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
address: kubernetes.default.{{.Values.cluster.dns}}
|
||||||
|
groups:
|
||||||
|
{{- if .Values.kubernetesAPI.groups }}
|
||||||
|
{{ toYaml .Values.kubernetesAPI.groups }}
|
||||||
|
{{- else }}
|
||||||
|
- {{ .Values.cluster.name }}-default-api-access
|
||||||
|
{{- end }}
|
||||||
|
name: {{ .Values.kubernetesAPI.resourceName | default "default-kubernetes-api" }}
|
||||||
|
networkID: ${NETWORK_ID}
|
||||||
|
{{- if .Values.kubernetesAPI.policies }}
|
||||||
|
policyName: "{{ join "," .Values.kubernetesAPI.policies }}"
|
||||||
|
{{- end }}
|
||||||
|
tcpPorts:
|
||||||
|
- 443
|
||||||
|
command:
|
||||||
|
- 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 -
|
||||||
|
serviceAccountName: {{ include "netbird-operator-config.serviceAccountName" . }}
|
||||||
|
restartPolicy: Never
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
{{- range $k, $v := $.Values.policies }}
|
||||||
|
---
|
||||||
|
apiVersion: netbird.io/v1
|
||||||
|
kind: NBPolicy
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
helm.sh/resource-policy: keep
|
||||||
|
finalizers:
|
||||||
|
- netbird.io/cleanup
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/component: operator
|
||||||
|
{{- include "netbird-operator-config.labels" $ | nindent 4 }}
|
||||||
|
name: {{ $k }}
|
||||||
|
spec:
|
||||||
|
name: {{ $v.name }}
|
||||||
|
sourceGroups:
|
||||||
|
{{ toYaml $v.sourceGroups | nindent 4}}
|
||||||
|
{{- if $v.description }}
|
||||||
|
description: {{ $v.description }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $v.protocols }}
|
||||||
|
protocols: {{ $v.protocols }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $v.ports }}
|
||||||
|
ports: {{ $v.ports }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if hasKey $v "bidirectional" }}
|
||||||
|
bidirectional: {{ $v.bidirectional }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
{{- if .Values.router.enabled }}
|
||||||
|
{{- if .Values.namespacedNetworks }}
|
||||||
|
{{ $defaults := .Values.router }}
|
||||||
|
{{ range $k, $v := .Values.router.namespaces }}
|
||||||
|
apiVersion: netbird.io/v1
|
||||||
|
kind: NBRoutingPeer
|
||||||
|
metadata:
|
||||||
|
finalizers:
|
||||||
|
- netbird.io/cleanup
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/component: operator
|
||||||
|
{{- include "netbird-operator-config.labels" $ | nindent 4 }}
|
||||||
|
name: router
|
||||||
|
namespace: {{ $k }}
|
||||||
|
{{ $spec := merge $defaults $v }}
|
||||||
|
{{- if or (or (or $spec.replicas $spec.resources) (or $spec.labels $spec.annotations)) (or $spec.nodeSelector $spec.tolerations) }}
|
||||||
|
spec:
|
||||||
|
{{- if $spec.replicas }}
|
||||||
|
replicas: {{ $spec.replicas }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $spec.resources }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml $spec.resources | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $spec.labels }}
|
||||||
|
labels:
|
||||||
|
{{- toYaml $spec.labels | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $spec.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml $spec.annotations | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $spec.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{- toYaml $spec.nodeSelector | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $spec.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{- toYaml $spec.tolerations | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
---
|
||||||
|
{{- end }}
|
||||||
|
{{- else }}
|
||||||
|
{{- with .Values.router }}
|
||||||
|
apiVersion: netbird.io/v1
|
||||||
|
kind: NBRoutingPeer
|
||||||
|
metadata:
|
||||||
|
finalizers:
|
||||||
|
- netbird.io/cleanup
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/component: operator
|
||||||
|
{{- include "netbird-operator-config.labels" $ | nindent 4 }}
|
||||||
|
name: router
|
||||||
|
{{- if or (or (or .replicas .resources) (or .labels .annotations)) (or .nodeSelector .tolerations) }}
|
||||||
|
spec:
|
||||||
|
{{- if .replicas }}
|
||||||
|
replicas: {{ .replicas }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .resources }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml .resources | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .labels }}
|
||||||
|
labels:
|
||||||
|
{{- toYaml .labels | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml .annotations | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{- toYaml .nodeSelector | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{- toYaml .tolerations | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: {{ include "netbird-operator-config.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "netbird-operator-config.labels" . | nindent 4 }}
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- netbird.io
|
||||||
|
resources:
|
||||||
|
- nbresources
|
||||||
|
verbs:
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- apiGroups:
|
||||||
|
- netbird.io
|
||||||
|
resources:
|
||||||
|
- nbroutingpeers
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- apiGroups:
|
||||||
|
- netbird.io
|
||||||
|
resources:
|
||||||
|
- nbresources/finalizers
|
||||||
|
verbs:
|
||||||
|
- update
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: {{ include "netbird-operator-config.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "netbird-operator-config.labels" . | nindent 4 }}
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: {{ include "netbird-operator-config.fullname" . }}
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: {{ include "netbird-operator-config.serviceAccountName" . }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{{- if and .Values.kubernetesAPI.enabled .Values.serviceAccount.create -}}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: {{ include "netbird-operator-config.serviceAccountName" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "netbird-operator-config.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.serviceAccount.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
automountServiceAccountToken: true
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
cluster:
|
||||||
|
name: "kubernetes"
|
||||||
|
dns: "svc.cluster.local"
|
||||||
|
|
||||||
|
# Create router per namespace, useful for strict networking requirements
|
||||||
|
namespacedNetworks: false
|
||||||
|
|
||||||
|
router:
|
||||||
|
# Deploy routing peer(s)
|
||||||
|
enabled: false
|
||||||
|
# replicas: 3
|
||||||
|
# resources:
|
||||||
|
# requests:
|
||||||
|
# cpu: 100m
|
||||||
|
# memory: 100Mi
|
||||||
|
# limits:
|
||||||
|
# cpu: 100m
|
||||||
|
# memory: 100Mi
|
||||||
|
# labels: {}
|
||||||
|
# annotations: {}
|
||||||
|
# nodeSelector: {}
|
||||||
|
# tolerations: []
|
||||||
|
# Only needed if namespacedNetworks is set to true
|
||||||
|
namespaces: {}
|
||||||
|
# default:
|
||||||
|
# replicas: 3
|
||||||
|
# resources:
|
||||||
|
# requests:
|
||||||
|
# cpu: 100m
|
||||||
|
# memory: 100Mi
|
||||||
|
# limits:
|
||||||
|
# cpu: 100m
|
||||||
|
# memory: 100Mi
|
||||||
|
# labels: {}
|
||||||
|
# annotations: {}
|
||||||
|
# nodeSelector: {}
|
||||||
|
# tolerations: []
|
||||||
|
# NetBird Policies for use with exposed services
|
||||||
|
policies: {}
|
||||||
|
# default:
|
||||||
|
# name: Kubernetes Default Policy
|
||||||
|
# sourceGroups:
|
||||||
|
# - All
|
||||||
|
|
||||||
|
kubernetesAPI:
|
||||||
|
enabled: false
|
||||||
|
groups: []
|
||||||
|
# - group1
|
||||||
|
# - group2
|
||||||
|
policies: []
|
||||||
|
# - default
|
||||||
|
# resourceName: "my-cluster-kubernetes"
|
||||||
|
|
||||||
|
serviceAccount:
|
||||||
|
create: true
|
||||||
|
name: ""
|
||||||
|
annotations: {}
|
||||||
@@ -151,7 +151,7 @@ func (r *NBGroupReconciler) handleDelete(ctx context.Context, nbGroup netbirdiov
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil && strings.Contains(err.Error(), "linked") {
|
if err != nil && strings.Contains(err.Error(), "linked") && !nbGroup.DeletionTimestamp.Add(time.Minute).Before(time.Now()) {
|
||||||
logger.Info("group still linked to resources on netbird", "err", err)
|
logger.Info("group still linked to resources on netbird", "err", err)
|
||||||
// Check if group is defined elsewhere in the cluster
|
// Check if group is defined elsewhere in the cluster
|
||||||
var groups netbirdiov1.NBGroupList
|
var groups netbirdiov1.NBGroupList
|
||||||
|
|||||||
@@ -2,11 +2,15 @@ package controller
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
nerrors "errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
@@ -23,6 +27,10 @@ import (
|
|||||||
"github.com/netbirdio/netbird/management/server/http/api"
|
"github.com/netbirdio/netbird/management/server/http/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errDuplicateResource = fmt.Errorf("duplicate resource")
|
||||||
|
)
|
||||||
|
|
||||||
// NBResourceReconciler reconciles a NBResource object
|
// NBResourceReconciler reconciles a NBResource object
|
||||||
type NBResourceReconciler struct {
|
type NBResourceReconciler struct {
|
||||||
client.Client
|
client.Client
|
||||||
@@ -87,6 +95,10 @@ func (r *NBResourceReconciler) Reconcile(ctx context.Context, req ctrl.Request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
resource, err := r.handleNetBirdResource(ctx, nbResource, groupIDs, logger)
|
resource, err := r.handleNetBirdResource(ctx, nbResource, groupIDs, logger)
|
||||||
|
if err != nil && nerrors.Is(err, errDuplicateResource) {
|
||||||
|
return ctrl.Result{RequeueAfter: defaultRequeueAfter}, nil
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
nbResource.Status.Conditions = netbirdiov1.NBConditionFalse("internalError", fmt.Sprintf("Error occurred handling NetBird Network Resource: %v", err))
|
nbResource.Status.Conditions = netbirdiov1.NBConditionFalse("internalError", fmt.Sprintf("Error occurred handling NetBird Network Resource: %v", err))
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
@@ -406,6 +418,12 @@ func (r *NBResourceReconciler) handleNetBirdResource(ctx context.Context, nbReso
|
|||||||
Name: nbResource.Spec.Name,
|
Name: nbResource.Spec.Name,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if err != nil && strings.Contains(err.Error(), "already exists") {
|
||||||
|
log.Log.Error(errNetBirdAPI, "network resource with the same name already exists", "err", err)
|
||||||
|
nbResource.Status.Conditions = netbirdiov1.NBConditionFalse("DuplicateName", "Resource name already exists")
|
||||||
|
return nil, errDuplicateResource
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(errNetBirdAPI, "error creating resource", "err", err)
|
logger.Error(errNetBirdAPI, "error creating resource", "err", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -562,6 +580,22 @@ func (r *NBResourceReconciler) handleGroups(ctx context.Context, req ctrl.Reques
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *NBResourceReconciler) handleDelete(ctx context.Context, req ctrl.Request, nbResource *netbirdiov1.NBResource, logger logr.Logger) error {
|
func (r *NBResourceReconciler) handleDelete(ctx context.Context, req ctrl.Request, nbResource *netbirdiov1.NBResource, logger logr.Logger) error {
|
||||||
|
var svc corev1.Service
|
||||||
|
err := r.Client.Get(ctx, req.NamespacedName, &svc)
|
||||||
|
if !errors.IsNotFound(err) {
|
||||||
|
logger.Error(errKubernetesAPI, "error getting Service", "err", err, "svc", req.NamespacedName.String())
|
||||||
|
return err
|
||||||
|
} else if err == nil {
|
||||||
|
if _, ok := svc.Annotations[ServiceExposeAnnotation]; ok {
|
||||||
|
delete(svc.Annotations, ServiceExposeAnnotation)
|
||||||
|
err = r.Client.Update(ctx, &svc)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error updating Service", "err", err, "svc", req.NamespacedName.String())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if nbResource.Status.PolicyName != nil {
|
if nbResource.Status.PolicyName != nil {
|
||||||
for _, policy := range util.SplitTrim(*nbResource.Status.PolicyName, ",") {
|
for _, policy := range util.SplitTrim(*nbResource.Status.PolicyName, ",") {
|
||||||
var nbPolicy netbirdiov1.NBPolicy
|
var nbPolicy netbirdiov1.NBPolicy
|
||||||
@@ -593,7 +627,7 @@ func (r *NBResourceReconciler) handleDelete(ctx context.Context, req ctrl.Reques
|
|||||||
}
|
}
|
||||||
|
|
||||||
nbGroupList := netbirdiov1.NBGroupList{}
|
nbGroupList := netbirdiov1.NBGroupList{}
|
||||||
err := r.Client.List(ctx, &nbGroupList, &client.ListOptions{Namespace: req.Namespace})
|
err = r.Client.List(ctx, &nbGroupList, &client.ListOptions{Namespace: req.Namespace})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(errKubernetesAPI, "error listing NBGroup", "err", err)
|
logger.Error(errKubernetesAPI, "error listing NBGroup", "err", err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -52,12 +52,6 @@ func (r *NBRoutingPeerReconciler) Reconcile(ctx context.Context, req ctrl.Reques
|
|||||||
|
|
||||||
originalNBRP := nbrp.DeepCopy()
|
originalNBRP := nbrp.DeepCopy()
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
|
||||||
// double check result is nil, otherwise error is not printed
|
|
||||||
// and exponential backoff doesn't work properly
|
|
||||||
res = ctrl.Result{}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if originalNBRP.DeletionTimestamp != nil && len(nbrp.Finalizers) == 0 {
|
if originalNBRP.DeletionTimestamp != nil && len(nbrp.Finalizers) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -67,6 +61,12 @@ func (r *NBRoutingPeerReconciler) Reconcile(ctx context.Context, req ctrl.Reques
|
|||||||
logger.Error(errKubernetesAPI, "error updating NBRoutingPeer Status", "err", err)
|
logger.Error(errKubernetesAPI, "error updating NBRoutingPeer Status", "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
// double check result is nil, otherwise error is not printed
|
||||||
|
// and exponential backoff doesn't work properly
|
||||||
|
res = ctrl.Result{}
|
||||||
|
return
|
||||||
|
}
|
||||||
if !res.Requeue && res.RequeueAfter == 0 {
|
if !res.Requeue && res.RequeueAfter == 0 {
|
||||||
res.RequeueAfter = defaultRequeueAfter
|
res.RequeueAfter = defaultRequeueAfter
|
||||||
}
|
}
|
||||||
@@ -210,7 +210,7 @@ func (r *NBRoutingPeerReconciler) handleDeployment(ctx context.Context, req ctrl
|
|||||||
nbrp.Status.Conditions = netbirdiov1.NBConditionFalse("internalError", fmt.Sprintf("error creating Deployment: %v", err))
|
nbrp.Status.Conditions = netbirdiov1.NBConditionFalse("internalError", fmt.Sprintf("error creating Deployment: %v", err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else if err == nil {
|
||||||
updatedDeployment := routingPeerDeployment.DeepCopy()
|
updatedDeployment := routingPeerDeployment.DeepCopy()
|
||||||
updatedDeployment.ObjectMeta.Name = nbrp.Name
|
updatedDeployment.ObjectMeta.Name = nbrp.Name
|
||||||
updatedDeployment.ObjectMeta.Namespace = nbrp.Namespace
|
updatedDeployment.ObjectMeta.Namespace = nbrp.Namespace
|
||||||
@@ -291,7 +291,7 @@ func (r *NBRoutingPeerReconciler) handleDeployment(ctx context.Context, req ctrl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleRouter reconcile network routing peer in NetBird management API
|
// handleRouter reconcile network routing peer in NetBird management API
|
||||||
@@ -393,6 +393,14 @@ func (r *NBRoutingPeerReconciler) handleSetupKey(ctx context.Context, req ctrl.R
|
|||||||
}
|
}
|
||||||
err = r.Client.Create(ctx, &skSecret)
|
err = r.Client.Create(ctx, &skSecret)
|
||||||
if errors.IsAlreadyExists(err) {
|
if errors.IsAlreadyExists(err) {
|
||||||
|
err = r.Client.Get(ctx, req.NamespacedName, &skSecret)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errNetBirdAPI, "error getting secret", "err", err)
|
||||||
|
return &ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
skSecret.Data = map[string][]byte{
|
||||||
|
"setupKey": []byte(setupKey.Key),
|
||||||
|
}
|
||||||
err = r.Client.Update(ctx, &skSecret)
|
err = r.Client.Update(ctx, &skSecret)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,7 +418,7 @@ func (r *NBRoutingPeerReconciler) handleSetupKey(ctx context.Context, req ctrl.R
|
|||||||
return &ctrl.Result{}, err
|
return &ctrl.Result{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil || setupKey.Revoked {
|
if (err != nil && strings.Contains(err.Error(), "not found")) || setupKey == nil || setupKey.Revoked {
|
||||||
if setupKey != nil && setupKey.Revoked {
|
if setupKey != nil && setupKey.Revoked {
|
||||||
err = r.netbird.SetupKeys.Delete(ctx, *nbrp.Status.SetupKeyID)
|
err = r.netbird.SetupKeys.Delete(ctx, *nbrp.Status.SetupKeyID)
|
||||||
|
|
||||||
@@ -586,16 +594,6 @@ func (r *NBRoutingPeerReconciler) handleDelete(ctx context.Context, req ctrl.Req
|
|||||||
logger.Info("Setup key deleted", "id", setupKeyID)
|
logger.Info("Setup key deleted", "id", setupKeyID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if nbrp.Status.RouterID != nil {
|
|
||||||
err = r.netbird.Networks.Routers(*nbrp.Status.NetworkID).Delete(ctx, *nbrp.Status.RouterID)
|
|
||||||
if err != nil && !strings.Contains(err.Error(), "not found") {
|
|
||||||
logger.Error(errNetBirdAPI, "error deleting Network Router", "err", err)
|
|
||||||
return ctrl.Result{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
nbrp.Status.RouterID = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
nbGroup := netbirdiov1.NBGroup{}
|
nbGroup := netbirdiov1.NBGroup{}
|
||||||
err = r.Client.Get(ctx, req.NamespacedName, &nbGroup)
|
err = r.Client.Get(ctx, req.NamespacedName, &nbGroup)
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
@@ -631,6 +629,7 @@ func (r *NBRoutingPeerReconciler) handleDelete(ctx context.Context, req ctrl.Req
|
|||||||
}
|
}
|
||||||
|
|
||||||
nbrp.Status.NetworkID = nil
|
nbrp.Status.NetworkID = nil
|
||||||
|
nbrp.Status.RouterID = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -912,10 +912,8 @@ var _ = Describe("NBRoutingPeer Controller", func() {
|
|||||||
})
|
})
|
||||||
When("NBRoutingPeer is set for deletion", func() {
|
When("NBRoutingPeer is set for deletion", func() {
|
||||||
networkDeleted := false
|
networkDeleted := false
|
||||||
routerDeleted := false
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
networkDeleted = false
|
networkDeleted = false
|
||||||
routerDeleted = false
|
|
||||||
nbroutingpeer.Status.SetupKeyID = util.Ptr("skid")
|
nbroutingpeer.Status.SetupKeyID = util.Ptr("skid")
|
||||||
Expect(k8sClient.Status().Update(ctx, nbroutingpeer)).To(Succeed())
|
Expect(k8sClient.Status().Update(ctx, nbroutingpeer)).To(Succeed())
|
||||||
|
|
||||||
@@ -953,14 +951,6 @@ var _ = Describe("NBRoutingPeer Controller", func() {
|
|||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
networkDeleted = true
|
networkDeleted = true
|
||||||
})
|
})
|
||||||
|
|
||||||
mux.HandleFunc("/api/networks/test/routers/test", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
defer GinkgoRecover()
|
|
||||||
Expect(r.Method).To(Equal(http.MethodDelete))
|
|
||||||
_, err = w.Write([]byte(`{}`))
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
routerDeleted = true
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("should remove finalizer from NBGroup", func() {
|
It("should remove finalizer from NBGroup", func() {
|
||||||
@@ -980,7 +970,7 @@ var _ = Describe("NBRoutingPeer Controller", func() {
|
|||||||
NamespacedName: typeNamespacedName,
|
NamespacedName: typeNamespacedName,
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(routerDeleted).To(BeTrue())
|
Expect(networkDeleted).To(BeTrue())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("should delete Network", func() {
|
It("should delete Network", func() {
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
||||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
|
||||||
|
|
||||||
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1"
|
|
||||||
"github.com/netbirdio/kubernetes-operator/internal/controller"
|
|
||||||
)
|
|
||||||
|
|
||||||
// nolint:unused
|
|
||||||
// log is for logging in this package.
|
|
||||||
var nbresourcelog = logf.Log.WithName("nbresource-resource")
|
|
||||||
|
|
||||||
// SetupNBResourceWebhookWithManager registers the webhook for NBResource in the manager.
|
|
||||||
func SetupNBResourceWebhookWithManager(mgr ctrl.Manager) error {
|
|
||||||
return ctrl.NewWebhookManagedBy(mgr).For(&netbirdiov1.NBResource{}).
|
|
||||||
WithValidator(&NBResourceCustomValidator{client: mgr.GetClient()}).
|
|
||||||
Complete()
|
|
||||||
}
|
|
||||||
|
|
||||||
// NBResourceCustomValidator struct is responsible for validating the NBResource resource
|
|
||||||
// when it is created, updated, or deleted.
|
|
||||||
type NBResourceCustomValidator struct {
|
|
||||||
client client.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ webhook.CustomValidator = &NBResourceCustomValidator{}
|
|
||||||
|
|
||||||
// ValidateCreate implements webhook.CustomValidator so a webhook will be registered for the type NBResource.
|
|
||||||
func (v *NBResourceCustomValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateUpdate implements webhook.CustomValidator so a webhook will be registered for the type NBResource.
|
|
||||||
func (v *NBResourceCustomValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateDelete implements webhook.CustomValidator so a webhook will be registered for the type NBResource.
|
|
||||||
func (v *NBResourceCustomValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
|
|
||||||
nbresource, ok := obj.(*netbirdiov1.NBResource)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("expected a NBResource object but got %T", obj)
|
|
||||||
}
|
|
||||||
nbresourcelog.Info("Validation for NBResource upon deletion", "name", nbresource.GetName())
|
|
||||||
|
|
||||||
var svc corev1.Service
|
|
||||||
err := v.client.Get(ctx, types.NamespacedName{Namespace: nbresource.Namespace, Name: nbresource.Name}, &svc)
|
|
||||||
if errors.IsNotFound(err) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := svc.Annotations[controller.ServiceExposeAnnotation]; ok && svc.DeletionTimestamp == nil {
|
|
||||||
return nil, fmt.Errorf("service %s/%s still has netbird.io/expose annotation", svc.Namespace, svc.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
. "github.com/onsi/ginkgo/v2"
|
|
||||||
. "github.com/onsi/gomega"
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
|
||||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
"k8s.io/apimachinery/pkg/util/intstr"
|
|
||||||
|
|
||||||
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ = Describe("NBResource Webhook", func() {
|
|
||||||
var (
|
|
||||||
obj *netbirdiov1.NBResource
|
|
||||||
oldObj *netbirdiov1.NBResource
|
|
||||||
validator NBResourceCustomValidator
|
|
||||||
)
|
|
||||||
|
|
||||||
BeforeEach(func() {
|
|
||||||
obj = &netbirdiov1.NBResource{}
|
|
||||||
oldObj = &netbirdiov1.NBResource{}
|
|
||||||
validator = NBResourceCustomValidator{
|
|
||||||
client: k8sClient,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
Context("When creating or updating NBResource under Validating Webhook", func() {
|
|
||||||
It("should allow creation", func() {
|
|
||||||
Expect(validator.ValidateCreate(ctx, obj)).Error().NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
It("should allow update", func() {
|
|
||||||
Expect(validator.ValidateUpdate(ctx, oldObj, obj)).Error().NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
When("No services are exposed", func() {
|
|
||||||
BeforeEach(func() {
|
|
||||||
obj.Name = "maw"
|
|
||||||
obj.Namespace = "default"
|
|
||||||
svc := &corev1.Service{
|
|
||||||
ObjectMeta: v1.ObjectMeta{
|
|
||||||
Name: "ne",
|
|
||||||
Namespace: "default",
|
|
||||||
},
|
|
||||||
Spec: corev1.ServiceSpec{
|
|
||||||
Ports: []corev1.ServicePort{
|
|
||||||
{
|
|
||||||
Protocol: corev1.ProtocolTCP,
|
|
||||||
Port: 80,
|
|
||||||
TargetPort: intstr.FromInt32(80),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
Expect(k8sClient.Create(ctx, svc)).To(Succeed())
|
|
||||||
})
|
|
||||||
AfterEach(func() {
|
|
||||||
svc := &netbirdiov1.NBResource{}
|
|
||||||
err := k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "ne"}, svc)
|
|
||||||
if !errors.IsNotFound(err) {
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
if len(svc.Finalizers) > 0 {
|
|
||||||
svc.Finalizers = nil
|
|
||||||
Expect(k8sClient.Update(ctx, svc)).To(Succeed())
|
|
||||||
}
|
|
||||||
err = k8sClient.Delete(ctx, svc)
|
|
||||||
if !errors.IsNotFound(err) {
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
It("should allow deletion", func() {
|
|
||||||
Expect(validator.ValidateDelete(ctx, obj)).Error().NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
When("A service is exposed", func() {
|
|
||||||
BeforeEach(func() {
|
|
||||||
obj.Name = "maw"
|
|
||||||
obj.Namespace = "default"
|
|
||||||
svc := &corev1.Service{
|
|
||||||
ObjectMeta: v1.ObjectMeta{
|
|
||||||
Name: "maw",
|
|
||||||
Namespace: "default",
|
|
||||||
Annotations: map[string]string{
|
|
||||||
"netbird.io/expose": "true",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Spec: corev1.ServiceSpec{
|
|
||||||
Ports: []corev1.ServicePort{
|
|
||||||
{
|
|
||||||
Protocol: corev1.ProtocolTCP,
|
|
||||||
Port: 80,
|
|
||||||
TargetPort: intstr.FromInt32(80),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
Expect(k8sClient.Create(ctx, svc)).To(Succeed())
|
|
||||||
})
|
|
||||||
AfterEach(func() {
|
|
||||||
svc := &corev1.Service{}
|
|
||||||
err := k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "maw"}, svc)
|
|
||||||
if !errors.IsNotFound(err) {
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
if len(svc.Finalizers) > 0 {
|
|
||||||
svc.Finalizers = nil
|
|
||||||
Expect(k8sClient.Update(ctx, svc)).To(Succeed())
|
|
||||||
}
|
|
||||||
err = k8sClient.Delete(ctx, svc)
|
|
||||||
if !errors.IsNotFound(err) {
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
It("should deny deletion", func() {
|
|
||||||
Expect(validator.ValidateDelete(ctx, obj)).Error().To(HaveOccurred())
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
||||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
|
||||||
|
|
||||||
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
// nolint:unused
|
|
||||||
// log is for logging in this package.
|
|
||||||
var nbroutingpeerlog = logf.Log.WithName("nbroutingpeer-resource")
|
|
||||||
|
|
||||||
// SetupNBRoutingPeerWebhookWithManager registers the webhook for NBRoutingPeer in the manager.
|
|
||||||
func SetupNBRoutingPeerWebhookWithManager(mgr ctrl.Manager) error {
|
|
||||||
return ctrl.NewWebhookManagedBy(mgr).For(&netbirdiov1.NBRoutingPeer{}).
|
|
||||||
WithValidator(&NBRoutingPeerCustomValidator{client: mgr.GetClient()}).
|
|
||||||
Complete()
|
|
||||||
}
|
|
||||||
|
|
||||||
// NBRoutingPeerCustomValidator struct is responsible for validating the NBRoutingPeer resource
|
|
||||||
// when it is created, updated, or deleted.
|
|
||||||
type NBRoutingPeerCustomValidator struct {
|
|
||||||
client client.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ webhook.CustomValidator = &NBRoutingPeerCustomValidator{}
|
|
||||||
|
|
||||||
// ValidateCreate implements webhook.CustomValidator so a webhook will be registered for the type NBRoutingPeer.
|
|
||||||
func (v *NBRoutingPeerCustomValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateUpdate implements webhook.CustomValidator so a webhook will be registered for the type NBRoutingPeer.
|
|
||||||
func (v *NBRoutingPeerCustomValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateDelete implements webhook.CustomValidator so a webhook will be registered for the type NBRoutingPeer.
|
|
||||||
func (v *NBRoutingPeerCustomValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
|
|
||||||
nbroutingpeer, ok := obj.(*netbirdiov1.NBRoutingPeer)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("expected a NBRoutingPeer object but got %T", obj)
|
|
||||||
}
|
|
||||||
nbroutingpeerlog.Info("Validation for NBRoutingPeer upon deletion", "name", nbroutingpeer.GetName())
|
|
||||||
|
|
||||||
if nbroutingpeer.Status.NetworkID == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var nbResources netbirdiov1.NBResourceList
|
|
||||||
err := v.client.List(ctx, &nbResources)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resourceValidator := &NBResourceCustomValidator{client: v.client}
|
|
||||||
|
|
||||||
for _, r := range nbResources.Items {
|
|
||||||
if r.Spec.NetworkID == *nbroutingpeer.Status.NetworkID {
|
|
||||||
_, err = resourceValidator.ValidateDelete(ctx, &r)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
@@ -1,242 +0,0 @@
|
|||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
. "github.com/onsi/ginkgo/v2"
|
|
||||||
. "github.com/onsi/gomega"
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
|
||||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
"k8s.io/apimachinery/pkg/util/intstr"
|
|
||||||
|
|
||||||
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1"
|
|
||||||
"github.com/netbirdio/kubernetes-operator/internal/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ = Describe("NBRoutingPeer Webhook", func() {
|
|
||||||
var (
|
|
||||||
obj *netbirdiov1.NBRoutingPeer
|
|
||||||
oldObj *netbirdiov1.NBRoutingPeer
|
|
||||||
validator NBRoutingPeerCustomValidator
|
|
||||||
)
|
|
||||||
|
|
||||||
BeforeEach(func() {
|
|
||||||
obj = &netbirdiov1.NBRoutingPeer{}
|
|
||||||
oldObj = &netbirdiov1.NBRoutingPeer{}
|
|
||||||
validator = NBRoutingPeerCustomValidator{
|
|
||||||
client: k8sClient,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
Context("When creating or updating NBRoutingPeer under Validating Webhook", func() {
|
|
||||||
It("should allow creation", func() {
|
|
||||||
Expect(validator.ValidateCreate(ctx, obj)).Error().NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
It("should allow update", func() {
|
|
||||||
Expect(validator.ValidateUpdate(ctx, oldObj, obj)).Error().NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
When("No NBResources Exist", func() {
|
|
||||||
It("should allow deletion", func() {
|
|
||||||
Expect(validator.ValidateDelete(ctx, obj)).Error().NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
})
|
|
||||||
When("Deleteable NBResources Exist", func() {
|
|
||||||
BeforeEach(func() {
|
|
||||||
nbResource := &netbirdiov1.NBResource{
|
|
||||||
ObjectMeta: v1.ObjectMeta{
|
|
||||||
Name: "isexist",
|
|
||||||
Namespace: "default",
|
|
||||||
},
|
|
||||||
Spec: netbirdiov1.NBResourceSpec{
|
|
||||||
Name: "test1",
|
|
||||||
NetworkID: "test2",
|
|
||||||
Address: "test3",
|
|
||||||
Groups: []string{"test"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
Expect(k8sClient.Create(ctx, nbResource)).To(Succeed())
|
|
||||||
|
|
||||||
obj = &netbirdiov1.NBRoutingPeer{
|
|
||||||
Status: netbirdiov1.NBRoutingPeerStatus{
|
|
||||||
NetworkID: util.Ptr("test2"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
AfterEach(func() {
|
|
||||||
nbResource := &netbirdiov1.NBResource{}
|
|
||||||
err := k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "isexist"}, nbResource)
|
|
||||||
if !errors.IsNotFound(err) {
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
if len(nbResource.Finalizers) > 0 {
|
|
||||||
nbResource.Finalizers = nil
|
|
||||||
Expect(k8sClient.Update(ctx, nbResource)).To(Succeed())
|
|
||||||
}
|
|
||||||
err = k8sClient.Delete(ctx, nbResource)
|
|
||||||
if !errors.IsNotFound(err) {
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
It("should allow deletion", func() {
|
|
||||||
Expect(validator.ValidateDelete(ctx, obj)).Error().NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
})
|
|
||||||
When("Exposed Services for Network Exist", func() {
|
|
||||||
BeforeEach(func() {
|
|
||||||
nbResource := &netbirdiov1.NBResource{
|
|
||||||
ObjectMeta: v1.ObjectMeta{
|
|
||||||
Name: "maw",
|
|
||||||
Namespace: "default",
|
|
||||||
},
|
|
||||||
Spec: netbirdiov1.NBResourceSpec{
|
|
||||||
Name: "test1",
|
|
||||||
NetworkID: "test2",
|
|
||||||
Address: "test3",
|
|
||||||
Groups: []string{"test"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
Expect(k8sClient.Create(ctx, nbResource)).To(Succeed())
|
|
||||||
|
|
||||||
svc := &corev1.Service{
|
|
||||||
ObjectMeta: v1.ObjectMeta{
|
|
||||||
Name: "maw",
|
|
||||||
Namespace: "default",
|
|
||||||
Annotations: map[string]string{
|
|
||||||
"netbird.io/expose": "true",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Spec: corev1.ServiceSpec{
|
|
||||||
Ports: []corev1.ServicePort{
|
|
||||||
{
|
|
||||||
Protocol: corev1.ProtocolTCP,
|
|
||||||
Port: 80,
|
|
||||||
TargetPort: intstr.FromInt32(80),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
Expect(k8sClient.Create(ctx, svc)).To(Succeed())
|
|
||||||
|
|
||||||
obj = &netbirdiov1.NBRoutingPeer{
|
|
||||||
Status: netbirdiov1.NBRoutingPeerStatus{
|
|
||||||
NetworkID: util.Ptr("test2"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
AfterEach(func() {
|
|
||||||
nbResource := &netbirdiov1.NBResource{}
|
|
||||||
err := k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "maw"}, nbResource)
|
|
||||||
if !errors.IsNotFound(err) {
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
if len(nbResource.Finalizers) > 0 {
|
|
||||||
nbResource.Finalizers = nil
|
|
||||||
Expect(k8sClient.Update(ctx, nbResource)).To(Succeed())
|
|
||||||
}
|
|
||||||
err = k8sClient.Delete(ctx, nbResource)
|
|
||||||
if !errors.IsNotFound(err) {
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
svc := &corev1.Service{}
|
|
||||||
err = k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "maw"}, svc)
|
|
||||||
if !errors.IsNotFound(err) {
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
if len(svc.Finalizers) > 0 {
|
|
||||||
svc.Finalizers = nil
|
|
||||||
Expect(k8sClient.Update(ctx, svc)).To(Succeed())
|
|
||||||
}
|
|
||||||
err = k8sClient.Delete(ctx, svc)
|
|
||||||
if !errors.IsNotFound(err) {
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
It("should deny deletion", func() {
|
|
||||||
Expect(validator.ValidateDelete(ctx, obj)).Error().To(HaveOccurred())
|
|
||||||
})
|
|
||||||
})
|
|
||||||
When("Exposed NBResources do not belong to network", func() {
|
|
||||||
BeforeEach(func() {
|
|
||||||
nbResource := &netbirdiov1.NBResource{
|
|
||||||
ObjectMeta: v1.ObjectMeta{
|
|
||||||
Name: "maw",
|
|
||||||
Namespace: "default",
|
|
||||||
},
|
|
||||||
Spec: netbirdiov1.NBResourceSpec{
|
|
||||||
Name: "test1",
|
|
||||||
NetworkID: "test5",
|
|
||||||
Address: "test3",
|
|
||||||
Groups: []string{"test"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
Expect(k8sClient.Create(ctx, nbResource)).To(Succeed())
|
|
||||||
|
|
||||||
svc := &corev1.Service{
|
|
||||||
ObjectMeta: v1.ObjectMeta{
|
|
||||||
Name: "maw",
|
|
||||||
Namespace: "default",
|
|
||||||
Annotations: map[string]string{
|
|
||||||
"netbird.io/expose": "true",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Spec: corev1.ServiceSpec{
|
|
||||||
Ports: []corev1.ServicePort{
|
|
||||||
{
|
|
||||||
Protocol: corev1.ProtocolTCP,
|
|
||||||
Port: 80,
|
|
||||||
TargetPort: intstr.FromInt32(80),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
Expect(k8sClient.Create(ctx, svc)).To(Succeed())
|
|
||||||
|
|
||||||
obj = &netbirdiov1.NBRoutingPeer{
|
|
||||||
Status: netbirdiov1.NBRoutingPeerStatus{
|
|
||||||
NetworkID: util.Ptr("test2"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
AfterEach(func() {
|
|
||||||
nbResource := &netbirdiov1.NBResource{}
|
|
||||||
err := k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "maw"}, nbResource)
|
|
||||||
if !errors.IsNotFound(err) {
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
if len(nbResource.Finalizers) > 0 {
|
|
||||||
nbResource.Finalizers = nil
|
|
||||||
Expect(k8sClient.Update(ctx, nbResource)).To(Succeed())
|
|
||||||
}
|
|
||||||
err = k8sClient.Delete(ctx, nbResource)
|
|
||||||
if !errors.IsNotFound(err) {
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
svc := &corev1.Service{}
|
|
||||||
err = k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "maw"}, svc)
|
|
||||||
if !errors.IsNotFound(err) {
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
if len(svc.Finalizers) > 0 {
|
|
||||||
svc.Finalizers = nil
|
|
||||||
Expect(k8sClient.Update(ctx, svc)).To(Succeed())
|
|
||||||
}
|
|
||||||
err = k8sClient.Delete(ctx, svc)
|
|
||||||
if !errors.IsNotFound(err) {
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
It("should allow deletion", func() {
|
|
||||||
Expect(validator.ValidateDelete(ctx, obj)).Error().NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
})
|
|
||||||
@@ -124,12 +124,6 @@ var _ = BeforeSuite(func() {
|
|||||||
err = SetupNBSetupKeyWebhookWithManager(mgr)
|
err = SetupNBSetupKeyWebhookWithManager(mgr)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
err = SetupNBResourceWebhookWithManager(mgr)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
err = SetupNBRoutingPeerWebhookWithManager(mgr)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
err = SetupNBGroupWebhookWithManager(mgr)
|
err = SetupNBGroupWebhookWithManager(mgr)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user